Merge "update getDPI with DisplayMetrics.DENSITY_DEVICE_STABLE"
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 cc4eb05..51c4d4d 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/CtsShimPrivUpgradeWrongSHA.apk"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 2c1b30b..c4296fb 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/CtsShimPrivUpgrade.apk"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 8bb986a..51eca9c 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/CtsShimPrivUpgradeWrongSHA.apk"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 e28a099..396adb4 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/CtsShimPrivUpgrade.apk"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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
new file mode 100644
index 0000000..4bea676
--- /dev/null
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_not_pre_installed_apex.asciipb
@@ -0,0 +1,13 @@
+drops {
+ android_build_drop {
+ build_id: "7396576"
+ target: "CtsShim"
+ source_file: "aosp_arm64/com.android.apex.cts.shim_not_pre_installed.apex"
+ }
+ dest_file: "hostsidetests/stagedinstall/testdata/apex//arm/com.android.apex.cts.shim_not_pre_installed.apex"
+ version: ""
+ version_group: ""
+ git_project: "platform/cts"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
+}
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 4c34b9d..fbdcf59 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v1.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 a40d92f..ccbcfcb 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_additional_file.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 b16eebb..f9ba098 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_additional_folder.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 6761a86..9c4ac9f 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 3e4b7fd..271f7d2 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 cc692d2..96d48cc 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_different_certificate.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 85724c3..730b9cb 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_different_package_name.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 adae35d..53a16396 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_no_hashtree.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 926c55f..fda2db4 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_sdk_target_p.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_sign_payload_with_different_key_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_sign_payload_with_different_key_apex.asciipb
new file mode 100644
index 0000000..2bcaf9b
--- /dev/null
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__arm_com_android_apex_cts_shim_v2_sign_payload_with_different_key_apex.asciipb
@@ -0,0 +1,13 @@
+drops {
+ android_build_drop {
+ build_id: "7396576"
+ target: "CtsShim"
+ source_file: "aosp_arm64/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex"
+ }
+ dest_file: "hostsidetests/stagedinstall/testdata/apex//arm/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex"
+ version: ""
+ version_group: ""
+ git_project: "platform/cts"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
+}
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 800edaa..6825a8c 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_signed_bob.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 8df4e67..5c8c69e 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_signed_bob_rot.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 3cf7696..9e43307 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 3a0383e..9299024 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_unsigned_payload.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 2c3cb4a..a4bd6f6 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_with_post_install_hook.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 f4326da..e3dcbc9 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_with_pre_install_hook.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 0d527d1..c727e61 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_without_apk_in_apex.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 183db3f..e769a1e 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v2_wrong_sha.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 4cfd096..05c7fc8 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v3.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 d699a7b..e21f3b5 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v3_signed_bob.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 4db830f..4707975 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/com.android.apex.cts.shim.v3_signed_bob_rot.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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
new file mode 100644
index 0000000..4b428fb
--- /dev/null
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_not_pre_installed_apex.asciipb
@@ -0,0 +1,13 @@
+drops {
+ android_build_drop {
+ build_id: "7396576"
+ target: "CtsShim"
+ source_file: "aosp_x86_64/com.android.apex.cts.shim_not_pre_installed.apex"
+ }
+ dest_file: "hostsidetests/stagedinstall/testdata/apex//x86/com.android.apex.cts.shim_not_pre_installed.apex"
+ version: ""
+ version_group: ""
+ git_project: "platform/cts"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
+}
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 5c4f161..4e5585d 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v1.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 58378c9..73bed47 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_additional_file.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 d88ead5..3b71d7f 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_additional_folder.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 f86bd15..ec1090a 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 3b040f2..df97a67 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 31c07e1..67abdb1 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_different_certificate.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 b19bcbb..02d684c 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_different_package_name.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 5344843..c5d24308 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_no_hashtree.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 8d97977..56444c5 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_sdk_target_p.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
diff --git a/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_sign_payload_with_different_key_apex.asciipb b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_sign_payload_with_different_key_apex.asciipb
new file mode 100644
index 0000000..d08793b
--- /dev/null
+++ b/.prebuilt_info/prebuilt_info_hostsidetests_stagedinstall_testdata_apex__x86_com_android_apex_cts_shim_v2_sign_payload_with_different_key_apex.asciipb
@@ -0,0 +1,13 @@
+drops {
+ android_build_drop {
+ build_id: "7396576"
+ target: "CtsShim"
+ source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex"
+ }
+ dest_file: "hostsidetests/stagedinstall/testdata/apex//x86/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex"
+ version: ""
+ version_group: ""
+ git_project: "platform/cts"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
+}
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 979d5ec..7478c60 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_signed_bob.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 88c6a14..2134eaa 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_signed_bob_rot.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 19da60b..202a61c 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_signed_bob_rot_rollback.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 e511c01..9e08ac9 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_unsigned_payload.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 8266f21..4b400bc 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_with_post_install_hook.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 737ee4c..859dbeb 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_with_pre_install_hook.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 df032f0..51bcfad 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_without_apk_in_apex.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 8700d88..b6177df 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v2_wrong_sha.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 400f61c..bfaece0 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v3.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 17ae337..7fba9ed 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v3_signed_bob.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 a825aba..62fffc2 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/com.android.apex.cts.shim.v3_signed_bob_rot.apex"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 f83e3be..1f4126b 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_arm64/CtsShimTargetPSdk.apk"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
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 89ebb7c..7fceac9 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: "6508977"
+ build_id: "7396576"
target: "CtsShim"
source_file: "aosp_x86_64/CtsShimTargetPSdk.apk"
}
@@ -8,5 +8,6 @@
version: ""
version_group: ""
git_project: "platform/cts"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
+ transform: TRANSFORM_NONE
}
diff --git a/apps/CameraITS/pymodules/its/cv2image.py b/apps/CameraITS/pymodules/its/cv2image.py
index 23c8734..09265e9 100644
--- a/apps/CameraITS/pymodules/its/cv2image.py
+++ b/apps/CameraITS/pymodules/its/cv2image.py
@@ -38,6 +38,7 @@
SCALE_RFOV_IN_WFOV_BOX = 0.67
SCALE_TELE_IN_RFOV_BOX = 0.67
SCALE_TELE_IN_WFOV_BOX = 0.5
+SCALE_SUPER_TELE_IN_RFOV_BOX = 0.5
VGA_HEIGHT = 480
VGA_WIDTH = 640
@@ -52,6 +53,9 @@
elif (camera_fov <= FOV_THRESH_TELE and
numpy.isclose(chart_distance, CHART_DISTANCE_WFOV, rtol=0.1)):
chart_scaling = SCALE_TELE_IN_WFOV_BOX
+ elif (camera_fov <= FOV_THRESH_SUPER_TELE and
+ numpy.isclose(chart_distance, CHART_DISTANCE_RFOV, rtol=0.1)):
+ chart_scaling = SCALE_SUPER_TELE_IN_RFOV_BOX
elif (camera_fov <= FOV_THRESH_TELE and
numpy.isclose(chart_distance, CHART_DISTANCE_RFOV, rtol=0.1)):
chart_scaling = SCALE_TELE_IN_RFOV_BOX
diff --git a/apps/CameraITS/pymodules/its/device.py b/apps/CameraITS/pymodules/its/device.py
index 2e2c775..ad97d48 100644
--- a/apps/CameraITS/pymodules/its/device.py
+++ b/apps/CameraITS/pymodules/its/device.py
@@ -228,7 +228,6 @@
self._camera_id = camera_id
self._hidden_physical_id = hidden_physical_id
- def __enter__(self):
# Initialize device id and adb command.
self.device_id = get_device_id()
self.adb = "adb -s " + self.device_id
@@ -236,6 +235,7 @@
self.__wait_for_service()
self.__init_socket_port()
+ def __enter__(self):
self.__close_camera()
self.__open_camera()
return self
@@ -961,6 +961,60 @@
else:
return rets[0]
+ def is_s_performance_class_primary_camera(self):
+ """Query whether the camera device is an S performance class primary camera.
+
+ A primary rear/front facing camera is a camera device with the lowest
+ camera Id for that facing.
+
+ Returns:
+ Boolean
+ """
+ cmd = {}
+ cmd['cmdName'] = 'isSPerformanceClassPrimaryCamera'
+ cmd['cameraId'] = self._camera_id
+ self.sock.send(json.dumps(cmd) + '\n')
+
+ data, _ = self.__read_response_from_socket()
+ if data['tag'] != 'sPerformanceClassPrimaryCamera':
+ raise error_util.CameraItsError('Failed to query S performance class '
+ 'primary camera')
+ return data['strValue'] == 'true'
+
+ def measure_camera_launch_ms(self):
+ """Measure camera launch latency in millisecond, from open to first frame.
+
+ Returns:
+ Camera launch latency from camera open to receipt of first frame
+ """
+ cmd = {}
+ cmd['cmdName'] = 'measureCameraLaunchMs'
+ cmd['cameraId'] = self._camera_id
+ self.sock.send(json.dumps(cmd) + '\n')
+
+ data, _ = self.__read_response_from_socket()
+ if data['tag'] != 'cameraLaunchMs':
+ raise error_util.CameraItsError('Failed to measure camera launch latency')
+ return float(data['strValue'])
+
+ def measure_camera_1080p_jpeg_capture_ms(self):
+ """Measure camera 1080P jpeg capture latency in milliseconds.
+
+ Returns:
+ Camera jpeg capture latency in milliseconds
+ """
+ cmd = {}
+ cmd['cmdName'] = 'measureCamera1080pJpegCaptureMs'
+ cmd['cameraId'] = self._camera_id
+ self.sock.send(json.dumps(cmd) + '\n')
+
+ data, _ = self.__read_response_from_socket()
+ if data['tag'] != 'camera1080pJpegCaptureMs':
+ raise error_util.CameraItsError(
+ 'Failed to measure camera 1080p jpeg capture latency')
+ return float(data['strValue'])
+
+
def do_capture_with_latency(cam, req, sync_latency, fmt=None):
"""Helper function to take enough frames with do_capture to allow sync latency.
diff --git a/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py b/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py
new file mode 100644
index 0000000..af24dea
--- /dev/null
+++ b/apps/CameraITS/tests/scene2_c/test_camera_launch_perf_class.py
@@ -0,0 +1,51 @@
+# Copyright 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Verify camera startup is < 500ms for both front and back primary cameras.
+"""
+
+import its.caps
+import its.device
+
+CAMERA_LAUNCH_S_PERFORMANCE_CLASS_THRESHOLD = 500 # ms
+
+
+def main():
+ """Test camera launch latency for S performance class as specified in CDD.
+
+ [7.5/H-1-7] MUST have camera2 startup latency (open camera to first preview
+ frame) < 500ms as measured by the CTS camera PerformanceTest under ITS
+ lighting conditions (3000K) for both primary cameras.
+ """
+
+ # Open camera with "with" semantics to check skip condition and save camera
+ # id
+ cam_id = ''
+ with its.device.ItsSession() as cam:
+ its.caps.skip_unless(
+ cam.is_s_performance_class_primary_camera())
+ cam_id = cam._camera_id
+
+ # Create an its session without opening the camera to test camera launch
+ # latency
+ session = its.device.ItsSession(camera_id=cam_id)
+
+ launch_ms = session.measure_camera_launch_ms()
+ print 'camera launch time: %.1f ms' % launch_ms
+
+ msg = 'camera launch time: %.1f ms, THRESH: %.1f ms' \
+ % (launch_ms, CAMERA_LAUNCH_S_PERFORMANCE_CLASS_THRESHOLD)
+ assert launch_ms < CAMERA_LAUNCH_S_PERFORMANCE_CLASS_THRESHOLD, msg
+
+if __name__ == '__main__':
+ main()
diff --git a/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py b/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py
new file mode 100644
index 0000000..2abeec2
--- /dev/null
+++ b/apps/CameraITS/tests/scene2_c/test_jpeg_capture_perf_class.py
@@ -0,0 +1,51 @@
+# Copyright 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Verify jpeg capture latency for both front and back primary cameras.
+"""
+
+import its.caps
+import its.device
+
+JPEG_CAPTURE_S_PERFORMANCE_CLASS_THRESHOLD = 1000 # ms
+
+
+def main():
+ """Test jpeg capture latency for S performance class as specified in CDD.
+
+ [7.5/H-1-6] MUST have camera2 JPEG capture latency < 1000ms for 1080p
+ resolution as measured by the CTS camera PerformanceTest under ITS lighting
+ conditions (3000K) for both primary cameras.
+ """
+
+ # Open camera with "with" semantics to check skip condition and save camera
+ # id
+ cam_id = ''
+ with its.device.ItsSession() as cam:
+ its.caps.skip_unless(
+ cam.is_s_performance_class_primary_camera())
+ cam_id = cam._camera_id
+
+ # Create an Its session without opening the camera to test camera jpeg
+ # capture latency because the test opens camera internally
+ session = its.device.ItsSession(camera_id=cam_id)
+
+ jpeg_capture_ms = session.measure_camera_1080p_jpeg_capture_ms()
+ print '1080p jpeg capture time: %.1f ms' % jpeg_capture_ms
+
+ msg = '1080p jpeg capture time: %.1f ms, THRESH: %.1f ms' \
+ % (jpeg_capture_ms, JPEG_CAPTURE_S_PERFORMANCE_CLASS_THRESHOLD)
+ assert jpeg_capture_ms < JPEG_CAPTURE_S_PERFORMANCE_CLASS_THRESHOLD, msg
+
+if __name__ == '__main__':
+ main()
diff --git a/apps/CameraITS/tests/scene3/test_lens_movement_reporting.py b/apps/CameraITS/tests/scene3/test_lens_movement_reporting.py
index 0862b3b..a229fdfd 100644
--- a/apps/CameraITS/tests/scene3/test_lens_movement_reporting.py
+++ b/apps/CameraITS/tests/scene3/test_lens_movement_reporting.py
@@ -55,8 +55,7 @@
data_set = {}
white_level = int(props['android.sensor.info.whiteLevel'])
min_fd = props['android.lens.info.minimumFocusDistance']
- fds = [af_fd, min_fd]
- fds = sorted(fds * NUM_IMGS)
+ fds = [af_fd] * NUM_IMGS + [min_fd] * NUM_IMGS
reqs = []
for i, fd in enumerate(fds):
reqs.append(its.objects.manual_capture_request(gain, exp))
@@ -170,8 +169,9 @@
assert np.isclose(min_sharp, max_sharp, rtol=SHARPNESS_TOL)
# assert reported location is close to assign location for min_fd
print 'Asserting lens location close to assigned fd for min_fd data'
- assert np.isclose(d_min_fd[NUM_IMGS*2-1]['loc'],
- d_min_fd[NUM_IMGS*2-1]['fd'], rtol=POSITION_TOL)
+ last_key = max(d_min_fd.keys()) # find last frame
+ assert np.isclose(d_min_fd[last_key]['loc'], d_min_fd[last_key]['fd'],
+ rtol=POSITION_TOL)
if __name__ == '__main__':
diff --git a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
index 0caf148..c0f5667 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
@@ -359,7 +359,7 @@
if i == 1:
# Save a debug visualization of the features that are being
# tracked in the first frame.
- frame = frames[i]
+ frame = frames[i-1]
for x, y in p0_filtered[st == 1]:
cv2.circle(frame, (x, y), 3, (100, 100, 255), -1)
its.image.write_image(frame, "%s_features.png" % NAME)
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 47dd4f5..92b4fc6 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -179,7 +179,7 @@
<category android:name="android.cts.intent.category.MANUAL_TEST" />
</intent-filter>
<meta-data android:name="test_category" android:value="@string/test_category_other" />
- <meta-data android:name="test_excluded_features" android:value="android.hardware.type.automotive" />
+ <meta-data android:name="test_excluded_features" android:value="android.hardware.type.automotive:android.hardware.type.watch" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
</activity>
@@ -1755,6 +1755,22 @@
android:value="multi_display_mode" />
</activity>
+ <activity android:name=".security.UnlockedDeviceRequiredTest"
+ android:label="@string/sec_unlocked_device_required_test"
+ android:configChanges="keyboardHidden|orientation|screenSize" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_security" />
+ <meta-data android:name="test_excluded_features"
+ android:value="android.software.lockscreen_disabled" />
+ <meta-data android:name="test_required_features"
+ android:value="android.software.device_admin:android.software.secure_lock_screen" />
+ <meta-data android:name="display_mode"
+ android:value="multi_display_mode" />
+ </activity>
+
<activity android:name=".security.LockConfirmBypassTest"
android:label="@string/lock_confirm_test_title"
android:configChanges="keyboardHidden|orientation|screenSize" >
@@ -5104,7 +5120,7 @@
<category android:name="android.cts.intent.category.MANUAL_TEST" />
</intent-filter>
<meta-data android:name="test_category" android:value="@string/test_category_instant_apps" />
- <meta-data android:name="test_excluded_features" android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.automotive" />
+ <meta-data android:name="test_excluded_features" android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.automotive:android.hardware.type.watch" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
</activity>
@@ -5115,7 +5131,7 @@
<category android:name="android.cts.intent.category.MANUAL_TEST" />
</intent-filter>
<meta-data android:name="test_category" android:value="@string/test_category_instant_apps" />
- <meta-data android:name="test_excluded_features" android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.automotive" />
+ <meta-data android:name="test_excluded_features" android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.automotive:android.hardware.type.watch" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
</activity>
@@ -5127,7 +5143,7 @@
</intent-filter>
<meta-data android:name="test_category" android:value="@string/test_category_instant_apps" />
<meta-data android:name="test_excluded_features"
- android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.automotive" />
+ android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.automotive:android.hardware.type.watch" />
<meta-data android:name="display_mode"
android:value="multi_display_mode" />
</activity>
diff --git a/apps/CtsVerifier/res/layout-small/positive_device_owner.xml b/apps/CtsVerifier/res/layout-small/positive_device_owner.xml
index 82f11a2..81f97f6 100644
--- a/apps/CtsVerifier/res/layout-small/positive_device_owner.xml
+++ b/apps/CtsVerifier/res/layout-small/positive_device_owner.xml
@@ -18,13 +18,16 @@
android:layout_height="match_parent"
android:orientation="vertical">
- <ScrollView
+
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="match_parent">
- <LinearLayout
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <ScrollView
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
+ android:layout_height="0px"
+ android:layout_weight="1">
<TextView
android:id="@+id/positive_device_owner_instructions"
@@ -32,19 +35,22 @@
android:layout_height="wrap_content"
android:text="@string/device_owner_positive_tests_instructions"
android:textSize="16dip" />
+ </ScrollView>
- <Button
- android:id="@+id/set_device_owner_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/set_device_owner_button_label" />
+ <Button
+ android:id="@+id/set_device_owner_button"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1"
+ android:text="@string/set_device_owner_button_label" />
- <ListView
- android:id="@+id/android:list"
- android:layout_width="match_parent"
- android:layout_height="800dip" />
+ <ListView
+ android:id="@+id/android:list"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1" />
- <include layout="@layout/pass_fail_buttons" />
- </LinearLayout>
- </ScrollView>
+ <include layout="@layout/pass_fail_buttons" />
+ </LinearLayout>
+
</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout-small/sensor_test.xml b/apps/CtsVerifier/res/layout-small/sensor_test.xml
index 96cf30a..348e321 100644
--- a/apps/CtsVerifier/res/layout-small/sensor_test.xml
+++ b/apps/CtsVerifier/res/layout-small/sensor_test.xml
@@ -16,7 +16,10 @@
<com.android.cts.verifier.BoxInsetLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:paddingTop="20dp"
+ android:paddingLeft="15dp"
+ android:paddingRight="15dp">
<ScrollView android:id="@+id/log_scroll_view"
app:ctsv_layout_box="all"
android:fillViewport="true"
diff --git a/apps/CtsVerifier/res/layout-small/wifi_lockdown.xml b/apps/CtsVerifier/res/layout-small/wifi_lockdown.xml
index f158976..59dd730 100644
--- a/apps/CtsVerifier/res/layout-small/wifi_lockdown.xml
+++ b/apps/CtsVerifier/res/layout-small/wifi_lockdown.xml
@@ -73,7 +73,7 @@
<ListView
android:id="@+id/android:list"
android:layout_width="match_parent"
- android:layout_height="200dip"/>
+ android:layout_height="230dip"/>
<include layout="@layout/pass_fail_buttons" />
</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout-watch/display_cutout.xml b/apps/CtsVerifier/res/layout-watch/display_cutout.xml
new file mode 100644
index 0000000..b1cfa01
--- /dev/null
+++ b/apps/CtsVerifier/res/layout-watch/display_cutout.xml
@@ -0,0 +1,289 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="20dp">
+
+ <TextView
+ android:id="@+id/enable_buttons_desc"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/top_buttons"
+ android:layout_marginLeft="30dp"
+ android:layout_marginRight="30dp"
+ android:text="@string/display_cutout_test_instruction"
+ android:textSize="12dp" />
+
+ <include
+ android:id="@+id/pass_fail_buttons"
+ layout="@layout/pass_fail_buttons"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/enable_buttons_desc"
+ android:layout_marginLeft="30dp"
+ android:layout_marginRight="30dp" />
+
+ <LinearLayout
+ android:id="@+id/top_buttons"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/display_cutout_test_button_size"
+ android:layout_alignParentTop="true"
+ android:orientation="horizontal"
+ android:visibility="gone">
+
+ <Button
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@drawable/display_cutout_test_button"
+ android:onClick="onButtonClicked"
+ android:text="0"
+ android:textSize="10dp" />
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+
+ <Button
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@drawable/display_cutout_test_button"
+ android:onClick="onButtonClicked"
+ android:text="1"
+ android:textSize="10dp" />
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+
+ <Button
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@drawable/display_cutout_test_button"
+ android:onClick="onButtonClicked"
+ android:text="2"
+ android:textSize="10dp" />
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+
+ <Button
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@drawable/display_cutout_test_button"
+ android:onClick="onButtonClicked"
+ android:text="3"
+ android:textSize="10dp" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/bottom_buttons"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/display_cutout_test_button_size"
+ android:layout_alignParentBottom="true"
+ android:orientation="horizontal"
+ android:visibility="gone">
+
+ <Button
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@drawable/display_cutout_test_button"
+ android:onClick="onButtonClicked"
+ android:text="11"
+ android:textSize="10dp" />
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+
+ <Button
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@drawable/display_cutout_test_button"
+ android:onClick="onButtonClicked"
+ android:text="10"
+ android:textSize="10dp" />
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+
+ <Button
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@drawable/display_cutout_test_button"
+ android:onClick="onButtonClicked"
+ android:text="9"
+ android:textSize="10dp" />
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1" />
+
+ <Button
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@drawable/display_cutout_test_button"
+ android:onClick="onButtonClicked"
+ android:text="8"
+ android:textSize="10dp" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/left_buttons"
+ android:layout_width="@dimen/display_cutout_test_button_size"
+ android:layout_height="match_parent"
+ android:layout_alignParentLeft="true"
+ android:layout_marginTop="@dimen/display_cutout_test_button_size"
+ android:layout_marginBottom="@dimen/display_cutout_test_button_size"
+ android:orientation="vertical"
+ android:visibility="gone">
+
+ <Button
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:background="@drawable/display_cutout_test_button"
+ android:onClick="onButtonClicked"
+ android:text="15"
+ android:textSize="10dp" />
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <Button
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:background="@drawable/display_cutout_test_button"
+ android:onClick="onButtonClicked"
+ android:text="14"
+ android:textSize="10dp" />
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <Button
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:background="@drawable/display_cutout_test_button"
+ android:onClick="onButtonClicked"
+ android:text="13"
+ android:textSize="10dp" />
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <Button
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:background="@drawable/display_cutout_test_button"
+ android:onClick="onButtonClicked"
+ android:text="12"
+ android:textSize="10dp" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/right_buttons"
+ android:layout_width="@dimen/display_cutout_test_button_size"
+ android:layout_height="match_parent"
+ android:layout_alignParentRight="true"
+ android:layout_marginTop="@dimen/display_cutout_test_button_size"
+ android:layout_marginBottom="@dimen/display_cutout_test_button_size"
+ android:orientation="vertical"
+ android:visibility="gone">
+
+ <Button
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:background="@drawable/display_cutout_test_button"
+ android:onClick="onButtonClicked"
+ android:text="4"
+ android:textSize="10dp" />
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <Button
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:background="@drawable/display_cutout_test_button"
+ android:onClick="onButtonClicked"
+ android:text="5"
+ android:textSize="10dp" />
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <Button
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:background="@drawable/display_cutout_test_button"
+ android:onClick="onButtonClicked"
+ android:text="6"
+ android:textSize="10dp" />
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <Button
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:background="@drawable/display_cutout_test_button"
+ android:onClick="onButtonClicked"
+ android:text="7"
+ android:textSize="10dp" />
+ </LinearLayout>
+
+ </RelativeLayout>
+</ScrollView>
diff --git a/apps/CtsVerifier/res/layout-watch/pass_fail_set_password_complexity.xml b/apps/CtsVerifier/res/layout-watch/pass_fail_set_password_complexity.xml
new file mode 100644
index 0000000..9ac5661
--- /dev/null
+++ b/apps/CtsVerifier/res/layout-watch/pass_fail_set_password_complexity.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:id="@+id/linear_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentStart="true"
+ android:layout_alignParentTop="true"
+ android:divider="@android:color/white"
+ android:orientation="vertical"
+ android:showDividers="middle">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/set_complexity_high_btn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/set_complexity_high_txt" />
+
+ <TextView
+ android:id="@+id/set_complexity_high_desc"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="none"
+ android:text="@string/set_complexity_high_desc" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/set_complexity_medium_btn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/set_complexity_medium_txt" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="none"
+ android:text="@string/set_complexity_medium_desc" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/set_complexity_low_btn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/set_complexity_low_txt" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="none"
+ android:text="@string/set_complexity_low_desc" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/set_complexity_none_btn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/set_complexity_none_txt" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="none"
+ android:text="@string/set_complexity_none_desc" />
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <include
+ layout="@layout/pass_fail_buttons"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/linear_layout" />
+ </RelativeLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout-watch/requesting_bugreport_device_owner.xml b/apps/CtsVerifier/res/layout-watch/requesting_bugreport_device_owner.xml
index 8aebbe6..ae7111a 100644
--- a/apps/CtsVerifier/res/layout-watch/requesting_bugreport_device_owner.xml
+++ b/apps/CtsVerifier/res/layout-watch/requesting_bugreport_device_owner.xml
@@ -39,7 +39,7 @@
<ListView
android:id="@+id/android:list"
android:layout_width="match_parent"
- android:layout_height="500dp"/>
+ android:layout_height="560dp"/>
<include layout="@layout/pass_fail_buttons"/>
</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/wifi_main.xml b/apps/CtsVerifier/res/layout/wifi_main.xml
index 67ecb9a..ae4179e 100644
--- a/apps/CtsVerifier/res/layout/wifi_main.xml
+++ b/apps/CtsVerifier/res/layout/wifi_main.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,69 +12,83 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- style="@style/RootLayoutPadding">
- <TextView android:id="@+id/wifi_ssid_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/wifi_ssid_label"
- style="@style/InstructionsSmallFont"
- />
- <EditText android:id="@+id/wifi_ssid"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/wifi_ssid_label"
- android:inputType="text"
- style="@style/InstructionsSmallFont"
- />
- <TextView android:id="@+id/wifi_psk_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/wifi_ssid"
- android:text="@string/wifi_psk_label"
- style="@style/InstructionsSmallFont"
- />
- <EditText android:id="@+id/wifi_psk"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/wifi_psk_label"
- android:inputType="textPassword"
- style="@style/InstructionsSmallFont"
- />
- <Button android:id="@+id/wifi_start_test_btn"
- android:text="@string/wifi_start_test_label"
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/wifi_info_scroll_view"
+ style="@style/RootLayoutPadding"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+
+ <RelativeLayout
+ android:id="@+id/wifi_ssid_label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/wifi_ssid_label"
+ style="@style/InstructionsSmallFont"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/wifi_ssid_label" />
+
+ <EditText
+ android:id="@+id/wifi_ssid"
+ style="@style/InstructionsSmallFont"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/wifi_ssid_label"
+ android:inputType="text" />
+
+ <TextView
+ android:id="@+id/wifi_psk_label"
+ style="@style/InstructionsSmallFont"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/wifi_ssid"
+ android:text="@string/wifi_psk_label" />
+
+ <EditText
+ android:id="@+id/wifi_psk"
+ style="@style/InstructionsSmallFont"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/wifi_psk_label"
+ android:inputType="textPassword" />
+
+ <Button
+ android:id="@+id/wifi_start_test_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/wifi_psk"
android:layout_centerHorizontal="true"
- />
+ android:text="@string/wifi_start_test_label" />
- <ScrollView android:id="@+id/wifi_info_scroll_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_below="@id/wifi_start_test_btn"
- >
- <TextView android:id="@+id/wifi_info"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+
+ <TextView
+ android:id="@+id/wifi_info"
style="@style/InstructionsSmallFont"
- />
- </ScrollView>
- <ProgressBar android:id="@+id/wifi_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_below="@id/wifi_info_scroll_view"
- android:indeterminate="true"
+ android:layout_below="@id/wifi_start_test_btn" />
+
+
+ <ProgressBar
+ android:id="@+id/wifi_progress"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/wifi_info"
android:layout_gravity="center"
- android:visibility="gone"
- />
- <include android:id="@+id/pass_fail_buttons"
+ android:indeterminate="true"
+ android:visibility="gone" />
+
+
+ <include
+ android:id="@+id/pass_fail_buttons"
+ layout="@layout/pass_fail_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- layout="@layout/pass_fail_buttons"/>
-</RelativeLayout>
+ android:layout_below="@id/wifi_progress" />
+ </RelativeLayout>
+</ScrollView>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index bbc3ae3..e27d3e2e 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -395,6 +395,12 @@
authentication with timeout 0 can only be accessed once per reader session.
</string>
+ <string name="sec_unlocked_device_required_test">Unlocked Device Required</string>
+ <string name="sec_unlocked_device_required_test_info">
+ This test ensures that keys created with setUnlockedDeviceRequired are usable when the
+ screen is unlocked but not when it is locked.
+ </string>
+
<!-- Strings for BluetoothActivity -->
<string name="bluetooth_test">Bluetooth Test</string>
<string name="bluetooth_test_info">
@@ -5462,6 +5468,29 @@
\nAlphanumeric, length at least 4</string>
<string name="set_complexity_low_desc">Any pattern, PIN or password</string>
<string name="set_complexity_none_desc">No restrictions</string>
+ <!-- Strings for UnlockedDeviceRequiredTest -->
+ <string name="unlock_req_config_lock_screen">Secure lock screen has not been set up. Go to
+ Settings -> Security to set up a lock screen.</string>
+ <string name="unlock_req_config_lock_screen_and_biometrics">Secure lock screen has not been set
+ up. Go to Settings -> Security to set up a lock screen and biometric unlock.</string>
+ <string name="unlock_req_config_biometrics">Biometric unlock has not been set up. Go to Settings
+ -> Security to set up biometric unlock.</string>
+ <string name="unlock_req_biometric_lock">Lock the screen, wait 5 seconds, then unlock with
+ biometrics.</string>
+ <!-- This message should only be displayed briefly immediately after the user has unlocked
+ the device; as soon as key access is verified this message will be updated. -->
+ <string name="unlock_req_unlocked">Verifying the key is accessible after the unlock...</string>
+ <string name="unlock_req_credential_lock">Lock the screen, wait 5 seconds, then unlock with
+ credentials.</string>
+ <string name="unlock_req_successful">Test completed successfully.</string>
+ <string name="unlock_req_failed_key_available_when_locked">Test failed; the key was available
+ when the device was locked.</string>
+ <string name="unlock_req_failed_key_unavailable_when_unlocked">Test failed; the key was not
+ available when the device was unlocked.</string>
+ <!-- While this state should never be reached since all possible states are accounted for
+ it is included just in case. -->
+ <string name="unlock_req_unknown_state">The test is in an unexpected state; please dismiss
+ this dialog and restart the test.</string>
<!-- Notification Bubble Tests-->
<string name="bubbles_notification_title">Bubble Notification Tests</string>
@@ -5618,11 +5647,9 @@
<string name="display_cutout_test">DisplayCutout Test</string>
<string name="display_cutout_test_instruction">\n
- This test is to make sure that the area inside the safe insets from the DisplayCutout should be
- fully visible and touchable. \n\n
- Please check the below items: \n
- 1. All buttons are fully visible \n
- 2. All buttons are clickable. \n
+ This test is to make sure that the area inside the safe insets from the DisplayCutout should be:\n
+ 1. Visible\n
+ 2. Clickable.\n
</string>
<string name="loopback_test_question">Does this device allow for the connection of a loopback audio peripheral?</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
index f9601de..39e8301 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
@@ -409,7 +409,7 @@
.loadClass("android.os.SystemProperties")
.getMethod("get", String.class);
String emulatorKernel = (String) getStringMethod.invoke("0",
- "ro.kernel.qemu");
+ "ro.boot.qemu");
if (emulatorKernel.equals("1")) {
return false;
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/RingerModeActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/RingerModeActivity.java
index d3fa699..9e27cb3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/RingerModeActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/RingerModeActivity.java
@@ -75,7 +75,9 @@
private boolean mUseFixedVolume;
private boolean mIsTelevision;
private boolean mIsSingleVolume;
+ private boolean mIsWatch;
private boolean mSkipRingerTests;
+ private boolean mSkipTouchSoundTests;
@Override
protected int getTitleResource() {
@@ -101,6 +103,8 @@
mIsSingleVolume = mContext.getResources().getBoolean(
Resources.getSystem().getIdentifier("config_single_volume", "bool", "android"));
mSkipRingerTests = mUseFixedVolume || mIsTelevision || mIsSingleVolume;
+ mIsWatch = packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH);
+ mSkipTouchSoundTests = mIsWatch;
}
// Test Setup
@@ -246,6 +250,12 @@
@Override
protected void test() {
+
+ if (mSkipTouchSoundTests) {
+ status = PASS;
+ return;
+ }
+
boolean touchSoundEnabled =
Settings.System.getInt(mContext.getContentResolver(),
Settings.System.SOUND_EFFECTS_ENABLED, 1) == 1;
@@ -276,6 +286,12 @@
@Override
protected void test() {
+
+ if (mSkipTouchSoundTests) {
+ status = PASS;
+ return;
+ }
+
// should hear sound after loadSoundEffects() called.
mAudioManager.loadSoundEffects();
try {
@@ -1101,7 +1117,7 @@
if (stream == AudioManager.STREAM_VOICE_CALL) {
// Voice call requires MODIFY_PHONE_STATE, so we should not be able to mute
mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0);
- assertTrue("Voice call stream (" + stream + ") should require MODIFY_PHONE_STATE "
+ assertFalse("Voice call stream (" + stream + ") should require MODIFY_PHONE_STATE "
+ "to mute.", mAudioManager.isStreamMute(stream));
} else {
mAudioManager.adjustStreamVolume(stream, AudioManager.ADJUST_MUTE, 0);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserService.java
index b776143..5a60ad0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserService.java
@@ -126,13 +126,11 @@
mCallback = new BLEAdvertiseCallback();
mScannableCallback = new BLEAdvertiseCallback();
mUnscannableCallback = new BLEAdvertiseCallback();
- // Medium is last. Android TV has a medium advertiser running already, and if only four
- // are available, that's the one we want to fail
mPowerLevel = new int[]{
AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW,
AdvertiseSettings.ADVERTISE_TX_POWER_LOW,
- AdvertiseSettings.ADVERTISE_TX_POWER_HIGH,
- AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM};
+ AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM,
+ AdvertiseSettings.ADVERTISE_TX_POWER_HIGH};
mPowerCallback = new HashMap<Integer, AdvertiseCallback>();
for (int x : mPowerLevel) {
mPowerCallback.put(x, new BLEAdvertiseCallback());
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerService.java
index 8496905..2bcd86a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerService.java
@@ -37,7 +37,6 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.UUID;
public class BleScannerService extends Service {
@@ -75,9 +74,6 @@
"com.google.cts.verifier.bluetooth.EXTRA_DATA";
private static final byte MANUFACTURER_TEST_ID = (byte)0x07;
- public static final UUID ATV_REMOTE_UUID =
- UUID.fromString("cbbfe0e1-f7f3-4206-84e0-84cbb3d09dfc");
- public static final int MEDIUM_POWER_DBM = -7;
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mAdapter;
@@ -85,7 +81,6 @@
private ScanCallback mCallback;
private Handler mHandler;
private String mOldMac;
- private boolean mMediumRcvd;
@Override
public void onCreate() {
@@ -94,7 +89,6 @@
mCallback = new BLEScanCallback();
mHandler = new Handler();
mOldMac = null;
- mMediumRcvd = false;
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mAdapter = mBluetoothManager.getAdapter();
@@ -117,9 +111,6 @@
BleAdvertiserService.POWER_LEVEL_DATA,
BleAdvertiserService.POWER_LEVEL_MASK)
.build());
- filters.add(new ScanFilter.Builder()
- .setServiceUuid(new ParcelUuid(ATV_REMOTE_UUID))
- .build());
settingBuilder.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY);
break;
case COMMAND_SCAN_WITH_FILTER:
@@ -175,7 +166,6 @@
ScanRecord record = result.getScanRecord();
String mac = result.getDevice().getAddress();
Map<ParcelUuid, byte[]> serviceData = record.getServiceData();
- List<ParcelUuid> serviceUuids = record.getServiceUuids();
if (serviceData.get(new ParcelUuid(BleAdvertiserService.POWER_LEVEL_UUID)) != null) {
byte[] data =
@@ -199,24 +189,6 @@
sendBroadcast(newIntent);
}
}
- if (data[2] == AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM) {
- mMediumRcvd = true;
- }
- }
- } else if (!mMediumRcvd && serviceUuids != null
- && serviceUuids.contains(new ParcelUuid(ATV_REMOTE_UUID))) {
- // If we're not receiving medium power advertising, allow Android TV Remote Service
- // advertising packets, which are medium power, to be counted
- String deviceMac = result.getDevice().getAddress();
- if (deviceMac != null && mOldMac != null && deviceMac.equals(mOldMac)) {
- Intent powerIntent = new Intent(BLE_POWER_LEVEL);
- powerIntent.putExtra(EXTRA_MAC_ADDRESS, deviceMac);
- // These packets don't include TxPower, assume a valid power level
- powerIntent.putExtra(EXTRA_POWER_LEVEL, MEDIUM_POWER_DBM);
- powerIntent.putExtra(EXTRA_RSSI, new Integer(result.getRssi()).toString());
- powerIntent.putExtra(EXTRA_POWER_LEVEL_BIT,
- AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM);
- sendBroadcast(powerIntent);
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/OWNERS b/apps/CtsVerifier/src/com/android/cts/verifier/camera/OWNERS
index 8ebd7b8..d1d18b4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/OWNERS
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/OWNERS
@@ -1,2 +1,2 @@
# Bug component: 41727
-include platform/frameworks/av:/camera/OWNER
\ No newline at end of file
+include platform/frameworks/av:/camera/OWNERS
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 7ce97fe..3fe4e72 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
@@ -35,6 +35,7 @@
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.DngCreator;
import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.cts.PerformanceTest;
import android.hardware.camera2.params.InputConfiguration;
import android.hardware.camera2.params.MeteringRectangle;
import android.hardware.camera2.params.OutputConfiguration;
@@ -49,12 +50,15 @@
import android.media.ImageWriter;
import android.media.Image.Plane;
import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.Vibrator;
import android.util.Log;
import android.util.Rational;
@@ -62,16 +66,24 @@
import android.util.SparseArray;
import android.view.Surface;
+import androidx.test.InstrumentationRegistry;
+
import com.android.ex.camera2.blocking.BlockingCameraManager;
import com.android.ex.camera2.blocking.BlockingCameraManager.BlockingOpenException;
import com.android.ex.camera2.blocking.BlockingStateCallback;
import com.android.ex.camera2.blocking.BlockingSessionCallback;
+import com.android.compatibility.common.util.ReportLog.Metric;
import com.android.cts.verifier.camera.its.StatsImage;
+import com.android.cts.verifier.camera.performance.CameraTestInstrumentation;
+import com.android.cts.verifier.camera.performance.CameraTestInstrumentation.MetricListener;
import com.android.cts.verifier.R;
import org.json.JSONArray;
import org.json.JSONObject;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@@ -136,6 +148,11 @@
// Supports at most RAW+YUV+JPEG, one surface each, plus optional background stream
private static final int MAX_NUM_OUTPUT_SURFACES = 4;
+ // Performance class S version number
+ private static final int PERFORMANCE_CLASS_S = Build.VERSION_CODES.R + 1;
+ private static final int PERFORMANCE_CLASS_LEVEL = SystemProperties.getInt(
+ "ro.odm.build.media_performance_class", 0);
+
public static final int SERVERPORT = 6000;
public static final String REGION_KEY = "regions";
@@ -231,6 +248,11 @@
private HandlerThread mSensorThread = null;
private Handler mSensorHandler = null;
+ // Camera test instrumentation
+ private CameraTestInstrumentation mCameraInstrumentation;
+ // Camera PerformanceTest metric
+ private final ArrayList<Metric> mResults = new ArrayList<Metric>();
+
private static final int SERIALIZER_SURFACES_ID = 2;
private static final int SERIALIZER_PHYSICAL_METADATA_ID = 3;
@@ -612,7 +634,7 @@
}
String line = input.readLine();
if (line == null) {
- Logt.i(TAG, "Socket readline retuned null (host disconnected)");
+ Logt.i(TAG, "Socket readline returned null (host disconnected)");
break;
}
processSocketCommand(line);
@@ -709,6 +731,15 @@
mSocketRunnableObj.sendResponse("ItsVersion", ITS_SERVICE_VERSION);
} else if ("isStreamCombinationSupported".equals(cmdObj.getString("cmdName"))) {
doCheckStreamCombination(cmdObj);
+ } else if ("isSPerformanceClassPrimaryCamera".equals(cmdObj.getString("cmdName"))) {
+ String cameraId = cmdObj.getString("cameraId");
+ doCheckSPerformanceClassPrimaryCamera(cameraId);
+ } else if ("measureCameraLaunchMs".equals(cmdObj.getString("cmdName"))) {
+ String cameraId = cmdObj.getString("cameraId");
+ doMeasureCameraLaunchMs(cameraId);
+ } else if ("measureCamera1080pJpegCaptureMs".equals(cmdObj.getString("cmdName"))) {
+ String cameraId = cmdObj.getString("cameraId");
+ doMeasureCamera1080pJpegCaptureMs(cameraId);
} else {
throw new ItsException("Unknown command: " + cmd);
}
@@ -1038,6 +1069,93 @@
}
}
+ private void doCheckSPerformanceClassPrimaryCamera(String cameraId) throws ItsException {
+ boolean isSPerfClass = (PERFORMANCE_CLASS_LEVEL == PERFORMANCE_CLASS_S);
+
+ if (mItsCameraIdList == null) {
+ mItsCameraIdList = ItsUtils.getItsCompatibleCameraIds(mCameraManager);
+ }
+ if (mItsCameraIdList.mCameraIds.size() == 0) {
+ throw new ItsException("No camera devices");
+ }
+ if (!mItsCameraIdList.mCameraIds.contains(cameraId)) {
+ throw new ItsException("Invalid cameraId " + cameraId);
+ }
+
+ boolean isPrimaryCamera = false;
+ try {
+ CameraCharacteristics c = mCameraManager.getCameraCharacteristics(cameraId);
+ Integer cameraFacing = c.get(CameraCharacteristics.LENS_FACING);
+ for (String id : mItsCameraIdList.mCameraIds) {
+ c = mCameraManager.getCameraCharacteristics(id);
+ Integer facing = c.get(CameraCharacteristics.LENS_FACING);
+ if (cameraFacing.equals(facing)) {
+ if (cameraId.equals(id)) {
+ isPrimaryCamera = true;
+ } else {
+ isPrimaryCamera = false;
+ }
+ break;
+ }
+ }
+ } catch (CameraAccessException e) {
+ throw new ItsException("Failed to get camera characteristics", e);
+ }
+
+ mSocketRunnableObj.sendResponse("sPerformanceClassPrimaryCamera",
+ (isSPerfClass && isPrimaryCamera) ? "true" : "false");
+ }
+
+ private double invokeCameraPerformanceTest(Class testClass, String testName,
+ String cameraId, String metricName) throws ItsException {
+ mResults.clear();
+ mCameraInstrumentation = new CameraTestInstrumentation();
+ MetricListener metricListener = new MetricListener() {
+ @Override
+ public void onResultMetric(Metric metric) {
+ mResults.add(metric);
+ }
+ };
+ mCameraInstrumentation.initialize(this, metricListener);
+
+ Bundle bundle = new Bundle();
+ bundle.putString("camera-id", cameraId);
+ bundle.putString("perf-measure", "on");
+ bundle.putString("perf-class-test", "on");
+ InstrumentationRegistry.registerInstance(mCameraInstrumentation, bundle);
+
+ JUnitCore testRunner = new JUnitCore();
+ Log.v(TAG, String.format("Execute Test: %s#%s", testClass.getSimpleName(), testName));
+ Request request = Request.method(testClass, testName);
+ Result runResult = testRunner.run(request);
+ if (!runResult.wasSuccessful()) {
+ throw new ItsException("Camera PerformanceTest " + testClass.getSimpleName() +
+ "#" + testName + " failed");
+ }
+
+ for (Metric m : mResults) {
+ if (m.getMessage().equals(metricName) && m.getValues().length == 1) {
+ return m.getValues()[0];
+ }
+ }
+
+ throw new ItsException("Failed to look up " + metricName +
+ " in Camera PerformanceTest result!");
+ }
+
+ private void doMeasureCameraLaunchMs(String cameraId) throws ItsException {
+ double launchMs = invokeCameraPerformanceTest(PerformanceTest.class,
+ "testCameraLaunch", cameraId, "camera_launch_average_time_for_all_cameras");
+ mSocketRunnableObj.sendResponse("cameraLaunchMs", Double.toString(launchMs));
+ }
+
+ private void doMeasureCamera1080pJpegCaptureMs(String cameraId) throws ItsException {
+ double jpegCaptureMs = invokeCameraPerformanceTest(PerformanceTest.class,
+ "testSingleCapture", cameraId,
+ "camera_capture_average_latency_for_all_cameras_jpeg");
+ mSocketRunnableObj.sendResponse("camera1080pJpegCaptureMs", Double.toString(jpegCaptureMs));
+ }
+
private void prepareImageReaders(Size[] outputSizes, int[] outputFormats, Size inputSize,
int inputFormat, int maxInputBuffers) {
closeImageReaders();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java
index 5f1243f..233e1bd 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java
@@ -23,6 +23,7 @@
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Telephony;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -237,6 +238,11 @@
case UserManager.DISALLOW_ADJUST_VOLUME:
return pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT);
case UserManager.DISALLOW_CONFIG_CELL_BROADCASTS:
+ final TelephonyManager tm =
+ context.getSystemService(TelephonyManager.class);
+ if (!tm.isSmsCapable()) {
+ return false;
+ }
// Get com.android.internal.R.bool.config_cellBroadcastAppLinks
final int resId = context.getResources().getIdentifier(
"config_cellBroadcastAppLinks", "bool", "android");
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/net/MultiNetworkConnectivityTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/net/MultiNetworkConnectivityTestActivity.java
index d6ab01f..f1deb8d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/net/MultiNetworkConnectivityTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/net/MultiNetworkConnectivityTestActivity.java
@@ -554,7 +554,7 @@
final NetworkCallback mWifiNetworkCallback = new NetworkCallback() {
@Override
public void onAvailable(Network network) {
- Log.i(TAG, "Wifi network available " + network.netId);
+ Log.i(TAG, "Wifi network available " + network);
stopTimerDisplayIfRequested();
mMultiNetworkValidator.onWifiNetworkConnected(network);
}
@@ -569,7 +569,7 @@
final NetworkCallback mCellularNetworkCallback = new NetworkCallback() {
@Override
public void onAvailable(Network network) {
- Log.i(TAG, "Cellular network available " + network.netId);
+ Log.i(TAG, "Cellular network available " + network);
stopTimerDisplayIfRequested();
mMultiNetworkValidator.onCellularNetworkConnected(network);
}
@@ -761,7 +761,7 @@
Network activeNetwork = mConnectivityManager.getActiveNetwork();
NetworkCapabilities activeNetworkCapabilities =
mConnectivityManager.getNetworkCapabilities(activeNetwork);
- Log.i(TAG, "Network capabilities for " + activeNetwork.netId + " "
+ Log.i(TAG, "Network capabilities for " + activeNetwork + " "
+ activeNetworkCapabilities.hasCapability(NET_CAPABILITY_INTERNET));
return activeNetworkCapabilities.hasTransport(transport)
&& activeNetworkCapabilities.hasCapability(NET_CAPABILITY_INTERNET);
@@ -774,7 +774,7 @@
boolean isNetworkConnected(Network network) {
NetworkInfo networkInfo = mConnectivityManager.getNetworkInfo(network);
boolean status = networkInfo != null && networkInfo.isConnectedOrConnecting();
- Log.i(TAG, "Network connection status " + network.netId + " " + status);
+ Log.i(TAG, "Network connection status " + network + " " + status);
return status;
}
@@ -786,7 +786,7 @@
/** Called when a wifi network is connected and available */
void onWifiNetworkConnected(Network network) {
- Log.i(TAG, "Wifi network connected " + network.netId);
+ Log.i(TAG, "Wifi network connected " + network);
}
void onWifiNetworkUnavailable() {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientTestSuite.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientTestSuite.java
index a9fd27a..91ef081 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientTestSuite.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientTestSuite.java
@@ -19,6 +19,7 @@
import java.util.ArrayList;
import android.content.Context;
+import android.content.pm.PackageManager;
/**
* Test suite to join a p2p group.
@@ -62,6 +63,10 @@
sTestSuite = new ArrayList<ReqTestCase>();
sTestSuite.add(new P2pClientPbcTestCase(context));
- sTestSuite.add(new P2pClientPinTestCase(context));
+
+ // Remove pin based client for automotive until b/184183917 is resolved.
+ if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ sTestSuite.add(new P2pClientPinTestCase(context));
+ }
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/security/OWNERS b/apps/CtsVerifier/src/com/android/cts/verifier/security/OWNERS
index 4241b61..ce787714 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/security/OWNERS
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/security/OWNERS
@@ -1,6 +1,6 @@
-# Bug template url: https://b.corp.google.com/issues/new?component=100560&template=63204 = per-file: CA*.java, Ca*.java, KeyChainTest.java
-# Bug template url: https://b.corp.google.com/issues/new?component=100560&template=63204 = per-file: LockConfirmBypassTest.java, SetNewPasswordComplexityTest.java
-# Bug component: 189335 = per-file: FingerprintBoundKeysTest.java, IdentityCredentialAuthentication.java, ProtectedConfirmationTest.java, ScreenLockBoundKeysTest.java
+# Bug template url: https://b.corp.google.com/issues/new?component=100560&template=63204 = per-file CA*.java, Ca*.java, KeyChainTest.java
+# Bug template url: https://b.corp.google.com/issues/new?component=100560&template=63204 = per-file LockConfirmBypassTest.java, SetNewPasswordComplexityTest.java
+# Bug component: 189335 = per-file FingerprintBoundKeysTest.java, IdentityCredentialAuthentication.java, ProtectedConfirmationTest.java, ScreenLockBoundKeysTest.java
per-file CA*.java, Ca*.java, KeyChainTest.java = alexkershaw@google.com, eranm@google.com, rubinxu@google.com, sandness@google.com, pgrafov@google.com
per-file LockConfirmBypassTest.java, SetNewPasswordComplexityTest.java = alexkershaw@google.com, eranm@google.com, rubinxu@google.com, sandness@google.com, pgrafov@google.com
per-file FingerprintBoundKeysTest.java, IdentityCredentialAuthentication.java, ProtectedConfirmationTest.java, ScreenLockBoundKeysTest.java = swillden@google.com
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/security/UnlockedDeviceRequiredTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/security/UnlockedDeviceRequiredTest.java
new file mode 100644
index 0000000..cdaee66
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/security/UnlockedDeviceRequiredTest.java
@@ -0,0 +1,625 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.security;
+
+import android.annotation.IntDef;
+import android.annotation.StringRes;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.Fragment;
+import android.app.FragmentTransaction;
+import android.app.KeyguardManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.hardware.biometrics.BiometricManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.util.Log;
+import android.widget.Button;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.cert.CertificateException;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+/**
+ * This test verifies a key created with #setUnlockedDeviceRequired is not accessible when the
+ * device is locked.
+ * Requirements:
+ * Pin / pattern / password must be set, and if the device supports biometric unlock this must be
+ * set as well.
+ * Test flow:
+ * 1. Verify a pin / pattern / password has been configured; if the device supports biometric
+ * unlock verify this has been configured as well. If not direct the user to Settings -> Security.
+ * 2. Prompt the user to lock the device and unlock with biometrics after 5 seconds.
+ * 3. Once notification of the SCREEN_OFF has been received verify the device is locked, then
+ * verify the key cannot be accessed.
+ * 4. When the device is unlocked verify the key is now accessible after the biometric unlock.
+ * 5. Repeat steps 2-4, this time prompting the user to unlock using the device credentials.
+ */
+public class UnlockedDeviceRequiredTest extends PassFailButtons.Activity {
+ private static final String TAG = "UnlockedDeviceRequiredTest";
+
+ /**
+ * This tag is used to display and, when necessary, remove the dialog to display the current
+ * test status to the user.
+ */
+ private static final String FRAGMENT_TAG = "test_dialog";
+
+ /** Alias for our key in the Android Key Store. */
+ private static final String KEY_NAME = "my_lock_key";
+ private static final byte[] SECRET_BYTE_ARRAY = new byte[]{1, 2, 3, 4, 5, 6};
+
+ private Resources mResources;
+ private HandlerThread mHandlerThread;
+ private ScreenStateChangeReceiver mReceiver;
+
+ private TestController mController;
+ private TestDialogFragment mDialogFragment;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.sec_screen_lock_keys_main);
+ getPassButton().setEnabled(false);
+ setPassFailButtonClickListeners();
+ setInfoResources(R.string.sec_unlocked_device_required_test,
+ R.string.sec_unlocked_device_required_test_info, -1);
+ mResources = getApplicationContext().getResources();
+
+ // There are no broadcasts / notifications when a device state changes between locked and
+ // unlocked, but these two actions are most closely related to when the device should
+ // transition to a new lock state. Since the lock state may not immediately change when
+ // one of these broadcasts is sent use a HandlerThread to run off the UI thread to wait for
+ // the device to complete the transition to the new lock state.
+ mController = new TestController(this);
+ mReceiver = new ScreenStateChangeReceiver(mController);
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
+ intentFilter.addAction(Intent.ACTION_USER_PRESENT);
+ mHandlerThread = new HandlerThread("receiver_thread");
+ mHandlerThread.start();
+ Handler handler = new Handler(mHandlerThread.getLooper());
+ registerReceiver(mReceiver, intentFilter, null, handler);
+
+ // The test button should only be available when the DialogFragment is not currently
+ // displayed. When the button is clicked a new test is started (or the previous test
+ // resumed if it did not run through to completion).
+ mDialogFragment = TestDialogFragment.createDialogFragment(mController);
+ Button startTestButton = findViewById(R.id.sec_start_test_button);
+ startTestButton.setOnClickListener(view -> {
+ mController.updateTestState(true);
+ showDialog();
+ });
+ }
+
+ /**
+ * Shows the dialog with the next steps required by the user, or a completion status if the
+ * test has finished.
+ */
+ public void showDialog() {
+ // Remove any previously displayed fragments.
+ FragmentTransaction transaction = getFragmentManager().beginTransaction();
+ Fragment fragment = getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
+ if (fragment != null) {
+ transaction.remove(fragment);
+ }
+ transaction.addToBackStack(null);
+
+ mDialogFragment = TestDialogFragment.createDialogFragment(mController);
+ mDialogFragment.show(transaction, FRAGMENT_TAG);
+ }
+
+ /**
+ * Updates the text within the {@link DialogFragment}'s {@link AlertDialog} with the current
+ * state of the test and any required user actions.
+ */
+ private void updateDialogText() {
+ Dialog dialog = mDialogFragment.getDialog();
+ if (dialog instanceof AlertDialog) {
+ ((AlertDialog) dialog).setMessage(mResources.getString(mController.getDialogMessage()));
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ // When the app is resumed update the dialog text to ensure the user is directed to the
+ // next required action.
+ updateDialogText();
+ }
+
+ /**
+ * Creates a symmetric key in the Android Key Store which can only be used after the user has
+ * unlocked the device.
+ */
+ private static void createKey() {
+ // Generate a key to decrypt payment credentials, tokens, etc.
+ try {
+ KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ keyStore.load(null);
+ KeyGenerator keyGenerator = KeyGenerator.getInstance(
+ KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
+
+ // Set the alias of the entry in Android KeyStore where the key will appear
+ // and the constraints (purposes) in the constructor of the Builder
+ keyGenerator.init(new KeyGenParameterSpec.Builder(KEY_NAME,
+ KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
+ .setUnlockedDeviceRequired(true)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
+ .build());
+ keyGenerator.generateKey();
+ } catch (NoSuchAlgorithmException | NoSuchProviderException
+ | InvalidAlgorithmParameterException | KeyStoreException
+ | CertificateException | IOException e) {
+ throw new RuntimeException("Failed to create a symmetric key", e);
+ }
+ }
+
+ /**
+ * Tries to encrypt some data with the generated key in {@link #createKey} which
+ * only works if the user has unlocked the device.
+ *
+ * @param shouldFail boolean indicating whether an exception is expected; this is intended to
+ * prevent extra Logcat entries when the encrypt fails as expected
+ */
+ private static boolean tryEncrypt(boolean shouldFail) {
+ try {
+ KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ keyStore.load(null);
+ SecretKey secretKey = (SecretKey) keyStore.getKey(KEY_NAME, null);
+ Cipher cipher = Cipher.getInstance(
+ KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/"
+ + KeyProperties.ENCRYPTION_PADDING_PKCS7);
+
+ // Try encrypting something, it will only work if the device is unlocked.
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+ cipher.doFinal(SECRET_BYTE_ARRAY);
+ return true;
+ } catch (Exception e) {
+ if (!shouldFail) {
+ Log.w(TAG, "", e);
+ }
+ return false;
+ }
+ }
+
+ /**
+ * {@link BroadcastReceiver} intended to receive notification when the device's lock state
+ * should be changing.
+ *
+ * <p>{@link Intent#ACTION_SCREEN_OFF} should be sent when the device's screen is shut off;
+ * shortly after this event the device should be locked. Similarly {@link
+ * Intent#ACTION_USER_PRESENT} should be sent when the device's screen is on, the device is
+ * unlocked, and the user should be present at the device. This receiver forwards the
+ * expected lock state change to the {@link TestController} to verify the device behaves as
+ * expected depending on the current state of the test.
+ */
+ private static class ScreenStateChangeReceiver extends BroadcastReceiver {
+ private TestController mController;
+
+ /**
+ * Private constructor that accepts the {@code controller} that will be used to drive the
+ * test when lock state changes occur.
+ */
+ private ScreenStateChangeReceiver(TestController controller) {
+ mController = controller;
+ }
+
+ /**
+ * Receives one of the registered broadcasts and sends the expected device state to the
+ * {@link TestController}.
+ */
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ switch (intent.getAction()) {
+ case Intent.ACTION_SCREEN_OFF:
+ mController.deviceStateChanged(true);
+ break;
+ case Intent.ACTION_USER_PRESENT:
+ mController.deviceStateChanged(false);
+ break;
+ default:
+ Log.w(TAG, "Ignoring unexpected broadcast: " + intent.getAction());
+ }
+ }
+ }
+
+ /**
+ * Controls the flow of the test, verifying the prereqs are met and the device behaves as
+ * expected based on the current state of the test.
+ */
+ private static class TestController {
+ /**
+ * Number of times to retry the lock state query after a device has started the transition
+ * to a new lock state. This is intended to allow time for the device to enter the new state
+ * as returned by {@link KeyguardManager#isDeviceLocked()}.
+ */
+ private static final int MAX_DEVICE_STATE_RETRIES = 20;
+ /**
+ * Time to sleep between lock state queries; this will allow the device up to one second to
+ * reach the new lock state before timing out.
+ */
+ private static final long DEVICE_STATE_SLEEP_TIME = 50;
+
+ /**
+ * The test has been initialized and is waiting to verify that the device has met the
+ * requirements for the test.
+ */
+ private static final int STATE_INITIALIZED = 0;
+ /**
+ * The test is waiting for the user to configure a pin / pattern / password and a biometric
+ * unlock (where applicable).
+ */
+ private static final int STATE_AWAITING_LOCK_SCREEN_CONFIG = 1;
+ /**
+ * The test is waiting for the user to configure a biometric unlock, but a pin / pattern /
+ * password is configured on the device.
+ */
+ private static final int STATE_AWAITING_BIOMETRIC_CONFIG = 2;
+ /**
+ * The test is waiting for the user to lock the device; after the lock the device should be
+ * unlocked via biometrics.
+ */
+ private static final int STATE_AWAITING_BIOMETRIC_LOCK = 3;
+ /**
+ * The test successfully verified the key was not available in the lock state; waiting for
+ * the user to unlock the device with biometrics to verify the key is available after the
+ * unlock.
+ */
+ private static final int STATE_BIOMETRIC_UNLOCK_COMPLETE = 4;
+ /**
+ * The test is waiting for the user to lock the device; after the lock the device should be
+ * unlocked via pin / pattern / password.
+ */
+ private static final int STATE_AWAITING_CREDENTIAL_LOCK = 5;
+ /**
+ * The test successfully verified the key was not available in the lock state; waiting for
+ * the user to unlock the device with the pin / pattern / password to verify the key is
+ * available after the unlock.
+ */
+ private static final int STATE_CREDENTIAL_UNLOCK_COMPLETE = 6;
+ /**
+ * The test failed since the key was available when the device was in the lock state.
+ */
+ private static final int STATE_FAILED_KEY_AVAILABLE_IN_LOCK_STATE = 7;
+ /**
+ * The test failed since the key was not available when the device was unlocked.
+ */
+ private static final int STATE_FAILED_KEY_NOT_AVAILABLE_IN_UNLOCKED_STATE = 8;
+ /**
+ * The test completed successfully.
+ */
+ private static final int STATE_TEST_SUCCESSFUL = 9;
+
+ @IntDef(value = {
+ STATE_INITIALIZED,
+ STATE_AWAITING_LOCK_SCREEN_CONFIG,
+ STATE_AWAITING_BIOMETRIC_CONFIG,
+ STATE_AWAITING_BIOMETRIC_LOCK,
+ STATE_BIOMETRIC_UNLOCK_COMPLETE,
+ STATE_AWAITING_CREDENTIAL_LOCK,
+ STATE_CREDENTIAL_UNLOCK_COMPLETE,
+ STATE_FAILED_KEY_AVAILABLE_IN_LOCK_STATE,
+ STATE_FAILED_KEY_NOT_AVAILABLE_IN_UNLOCKED_STATE,
+ STATE_TEST_SUCCESSFUL,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface TestState {
+ }
+
+ private BiometricManager mBiometricManager;
+ private KeyguardManager mKeyguardManager;
+ private @TestState int mTestState;
+ private boolean mBiometricsSupported;
+ private UnlockedDeviceRequiredTest mActivity;
+
+ private TestController(UnlockedDeviceRequiredTest activity) {
+ mBiometricManager = activity.getSystemService(BiometricManager.class);
+ mKeyguardManager = activity.getSystemService(KeyguardManager.class);
+ // Initially assume biometrics are supported; when checking if test requirements are
+ // satisfied this can be set to false if the hardware is not available.
+ mBiometricsSupported = true;
+ mActivity = activity;
+ }
+
+ /**
+ * Updates the current state of the test based on whether the test's requirements are met;
+ * if {@code startNewTest} is true this will also start a new test if the previous test
+ * reached a terminal state.
+ */
+ private void updateTestState(boolean startNewTest) {
+ // If the test requirements are not met then return now as the verification process
+ // will set the appropriate test state based on what needs to be configured.
+ if (!verifyTestRequirements()) {
+ return;
+ }
+ // If the test was just initialized, requirements just satisfied, or a terminal state
+ // was reached then update the state to the first applicable test to be performed.
+ @TestState int initialTestState = STATE_AWAITING_BIOMETRIC_LOCK;
+ if (!mBiometricsSupported) {
+ initialTestState = STATE_AWAITING_CREDENTIAL_LOCK;
+ }
+ switch (mTestState) {
+ case STATE_INITIALIZED:
+ case STATE_AWAITING_LOCK_SCREEN_CONFIG:
+ case STATE_AWAITING_BIOMETRIC_CONFIG:
+ // When starting a new test recreate the key in case there are any problems
+ // accessing the key on previous attempts.
+ createKey();
+ mTestState = initialTestState;
+ break;
+ case STATE_FAILED_KEY_AVAILABLE_IN_LOCK_STATE:
+ case STATE_FAILED_KEY_NOT_AVAILABLE_IN_UNLOCKED_STATE:
+ case STATE_TEST_SUCCESSFUL: {
+ if (startNewTest) {
+ mTestState = initialTestState;
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Called when the device should be entering a new lock state; verifies if the test is in
+ * a state where the new lock state is expected and if so runs the next portion of the test.
+ *
+ * @param enteringLockState boolean indicating whether the device should be entering a
+ * locked state
+ */
+ private void deviceStateChanged(boolean enteringLockState) {
+ // The tests should only be run once the device meets the requirements.
+ if (verifyTestRequirements()) {
+ // If the device is entering a lock state then run any of the awaiting lock tests.
+ if (enteringLockState) {
+ if (mTestState == STATE_AWAITING_BIOMETRIC_LOCK
+ || mTestState == STATE_AWAITING_CREDENTIAL_LOCK) {
+ runDeviceTest(enteringLockState);
+ }
+ } else {
+ // else the device is entering an unlocked state; if a previous lock state was
+ // verified then run the unlock test now.
+ if (mTestState == STATE_BIOMETRIC_UNLOCK_COMPLETE ||
+ mTestState == STATE_CREDENTIAL_UNLOCK_COMPLETE) {
+ runDeviceTest(enteringLockState);
+ }
+ }
+ }
+ // Once the test has completed update the dialog's text to prompt the user for the next
+ // required action or to show the completion of the test.
+ mActivity.runOnUiThread(() -> mActivity.updateDialogText());
+ // Once the test completes successfully enable the pass button.
+ if (mTestState == STATE_TEST_SUCCESSFUL) {
+ mActivity.runOnUiThread(() -> mActivity.getPassButton().setEnabled(true));
+ }
+ }
+
+ /**
+ * Runs the next portion of the test based on the device's lock state.
+ *
+ * <p>This method will first wait for the device to reach the expected lock state since it
+ * can take some time from a lock state change event before the device is actually locked.
+ * If the test fails the lock state is verified again in case the user modified the lock
+ * state after the previous lock state was verified.
+ *
+ * @param enteringLockState boolean indicating whether the device should be entering a
+ * locked state.
+ */
+ private void runDeviceTest(boolean enteringLockState) {
+ // Wait for the device to reach the expected lock state before attempting the test.
+ if (waitForDeviceState(enteringLockState)) {
+ boolean encryptSuccessful = tryEncrypt(enteringLockState);
+ // The test has failed if the encryption success is the same as the lock state; if
+ // the device is being locked then the encryption should fail, and if the device is
+ // being unlocked the encryption should be successful.
+ if (encryptSuccessful == enteringLockState) {
+ // The test was expected to fail; run one more check to ensure the device
+ // is still in the expected lock state since it's possible the user locked /
+ // unlocked the device after its state was previously verified.
+ if (mKeyguardManager.isDeviceLocked() == enteringLockState) {
+ // The test failed; set the appropriate failed state.
+ if (enteringLockState) {
+ mTestState = STATE_FAILED_KEY_AVAILABLE_IN_LOCK_STATE;
+ } else {
+ mTestState = STATE_FAILED_KEY_NOT_AVAILABLE_IN_UNLOCKED_STATE;
+ }
+ } else {
+ Log.d(TAG, "Device state was changed while running test; need to"
+ + " retry the current test");
+ }
+ } else {
+ // The current test passed; update the state to prompt the user for the next
+ // event.
+ if (enteringLockState) {
+ if (mTestState == STATE_AWAITING_BIOMETRIC_LOCK) {
+ mTestState = STATE_BIOMETRIC_UNLOCK_COMPLETE;
+ } else {
+ mTestState = STATE_CREDENTIAL_UNLOCK_COMPLETE;
+ }
+ } else {
+ if (mTestState == STATE_BIOMETRIC_UNLOCK_COMPLETE) {
+ mTestState = STATE_AWAITING_CREDENTIAL_LOCK;
+ } else {
+ mTestState = STATE_TEST_SUCCESSFUL;
+ }
+ }
+ }
+ } else {
+ Log.w(TAG, "The device did not reach the "
+ + (enteringLockState ? "locked" : "unlocked")
+ + " state within the timeout period; this may need to be increased for"
+ + " future tests");
+ }
+ }
+
+ /**
+ * Waits for the lock state of the device as returned by {@link
+ * KeyguardManager#isDeviceLocked()} to match the expected state, returning {@code true} if
+ * the device reached the expected state within the timeout period.
+ */
+ private boolean waitForDeviceState(boolean enteringLockState) {
+ int numRetries = 0;
+ while (numRetries < MAX_DEVICE_STATE_RETRIES) {
+ numRetries++;
+ boolean lockState = mKeyguardManager.isDeviceLocked();
+ if (lockState == enteringLockState) {
+ return true;
+ }
+ try {
+ Thread.sleep(DEVICE_STATE_SLEEP_TIME);
+ } catch (InterruptedException e) {
+ Log.w(TAG, "Caught an Exception while sleeping: ", e);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Verifies the device meets the requirements that a pin / pattern / password is set and
+ * that a biometric unlock is configured where supported.
+ *
+ * <p>If the device does not meet the requirements for the test then the test state is
+ * updated to indicate the unmet requirements to ensure the user is prompted to resolve
+ * this.
+ *
+ * @return {@code true} if the device meets the requirements for the test
+ */
+ private boolean verifyTestRequirements() {
+ if (!mKeyguardManager.isDeviceSecure()) {
+ mTestState = STATE_AWAITING_LOCK_SCREEN_CONFIG;
+ return false;
+ }
+ boolean requirementsMet = true;
+ // If the device was previously verified to not support biometric unlock then do not run
+ // this verification again.
+ if (mBiometricsSupported) {
+ int biometricResponse = mBiometricManager.canAuthenticate(
+ BiometricManager.Authenticators.BIOMETRIC_STRONG);
+ switch (biometricResponse) {
+ // If the device does not have the hardware to support biometrics then set the
+ // boolean to indicate the lack of support to prevent this check on future
+ // invocations.
+ case BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE:
+ mBiometricsSupported = false;
+ requirementsMet = true;
+ break;
+ // A success response indicates at least one biometric is registered for device
+ // unlock.
+ case BiometricManager.BIOMETRIC_SUCCESS:
+ requirementsMet = true;
+ break;
+ case BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED:
+ mTestState = STATE_AWAITING_BIOMETRIC_CONFIG;
+ requirementsMet = false;
+ break;
+ // Treat any other response as a biometric unlock still needs to be configured.
+ default:
+ mTestState = STATE_AWAITING_BIOMETRIC_CONFIG;
+ Log.w(TAG,
+ "An unexpected response was received when querying "
+ + "BiometricManager#canAuthenticate: " + biometricResponse);
+ requirementsMet = false;
+ break;
+ }
+ }
+ return requirementsMet;
+ }
+
+ /**
+ * Returns the dialog message that should be displayed to the user based on the current
+ * state of the test.
+ */
+ private @StringRes int getDialogMessage() {
+ // Update the test state in case it was recently initialized to ensure the next
+ // required user action is displayed.
+ updateTestState(false);
+ switch (mTestState) {
+ case STATE_AWAITING_LOCK_SCREEN_CONFIG:
+ if (mBiometricsSupported) {
+ return R.string.unlock_req_config_lock_screen_and_biometrics;
+ }
+ return R.string.unlock_req_config_lock_screen;
+ case STATE_AWAITING_BIOMETRIC_CONFIG:
+ return R.string.unlock_req_config_biometrics;
+ case STATE_AWAITING_BIOMETRIC_LOCK:
+ return R.string.unlock_req_biometric_lock;
+ case STATE_BIOMETRIC_UNLOCK_COMPLETE:
+ case STATE_CREDENTIAL_UNLOCK_COMPLETE:
+ return R.string.unlock_req_unlocked;
+ case STATE_AWAITING_CREDENTIAL_LOCK:
+ return R.string.unlock_req_credential_lock;
+ case STATE_TEST_SUCCESSFUL:
+ return R.string.unlock_req_successful;
+ case STATE_FAILED_KEY_AVAILABLE_IN_LOCK_STATE:
+ return R.string.unlock_req_failed_key_available_when_locked;
+ case STATE_FAILED_KEY_NOT_AVAILABLE_IN_UNLOCKED_STATE:
+ return R.string.unlock_req_failed_key_unavailable_when_unlocked;
+ // While all states are accounted for a default return is required; report an
+ // unknown state if this is reached to ensure the test is retried from a clean
+ // state.
+ default:
+ return R.string.unlock_req_unknown_state;
+ }
+ }
+ }
+
+ /**
+ * {@link DialogFragment} used to display an AlertDialog to guide the user through the steps
+ * required for the test. A {@code DialogFragment} is used since it automatically handles
+ * configuration changes.
+ */
+ public static class TestDialogFragment extends DialogFragment {
+ private TestController mController;
+
+ /**
+ * Creates a new {@link DialogFragment} that can obtain its text from the provided {@code
+ * controller}.
+ */
+ private static TestDialogFragment createDialogFragment(TestController controller) {
+ TestDialogFragment fragment = new TestDialogFragment();
+ fragment.mController = controller;
+ return fragment;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ return new AlertDialog.Builder(getContext()).setMessage(
+ mController.getDialogMessage()).create();
+ }
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/CallbackUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/CallbackUtils.java
index 38c2f11..d432ef9 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/CallbackUtils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/CallbackUtils.java
@@ -17,7 +17,6 @@
package com.android.cts.verifier.wifi;
import android.net.ConnectivityManager;
-import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.util.Log;
@@ -59,11 +58,9 @@
}
@Override
- public void onAvailable(Network network, NetworkCapabilities networkCapabilities,
- LinkProperties linkProperties, boolean isBlocked) {
+ public void onAvailable(Network network) {
if (DBG) Log.v(TAG, "onAvailable");
mNetwork = network;
- mNetworkCapabilities = networkCapabilities;
mOnAvailableBlocker.countDown();
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkRequestTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkRequestTestCase.java
index 75e5a42..a19edf3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkRequestTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkRequestTestCase.java
@@ -248,7 +248,7 @@
@Override
protected void setUp() {
super.setUp();
- mConnectivityManager = ConnectivityManager.from(mContext);
+ mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
}
@Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkSuggestionTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkSuggestionTestCase.java
index 1a829f2..49d5d80 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkSuggestionTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifi/testcase/NetworkSuggestionTestCase.java
@@ -407,7 +407,7 @@
@Override
protected void setUp() {
super.setUp();
- mConnectivityManager = ConnectivityManager.from(mContext);
+ mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
}
@Override
diff --git a/apps/MainlineModuleDetector/Android.mk b/apps/MainlineModuleDetector/Android.mk
index 6202ac7..2d84f02 100644
--- a/apps/MainlineModuleDetector/Android.mk
+++ b/apps/MainlineModuleDetector/Android.mk
@@ -26,6 +26,8 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := MainlineModuleDetector
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_SDK_VERSION := current
diff --git a/apps/hotspot/Android.bp b/apps/hotspot/Android.bp
new file mode 100644
index 0000000..6fe89c3
--- /dev/null
+++ b/apps/hotspot/Android.bp
@@ -0,0 +1,17 @@
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "hotspot",
+ defaults: ["cts_defaults"],
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+ static_libs: ["android-support-v4"],
+ test_suites: [
+ "cts",
+ "general-tests",
+ "sts",
+ ],
+}
diff --git a/apps/hotspot/Android.mk b/apps/hotspot/Android.mk
deleted file mode 100644
index ce3b1ca1..0000000
--- a/apps/hotspot/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := hotspot
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
-
-LOCAL_COMPATIBILITY_SUITE := cts general-tests sts
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/build/device_info_package.mk b/build/device_info_package.mk
index a79e848..2f5b095 100644
--- a/build/device_info_package.mk
+++ b/build/device_info_package.mk
@@ -37,7 +37,6 @@
$(DEVICE_INFO_PACKAGE).MediaDeviceInfo \
$(DEVICE_INFO_PACKAGE).MemoryDeviceInfo \
$(DEVICE_INFO_PACKAGE).PackageDeviceInfo \
- $(DEVICE_INFO_PACKAGE).PropertyDeviceInfo \
$(DEVICE_INFO_PACKAGE).ScreenDeviceInfo \
$(DEVICE_INFO_PACKAGE).StorageDeviceInfo \
$(DEVICE_INFO_PACKAGE).UserDeviceInfo \
diff --git a/build/test_executable.mk b/build/test_executable.mk
index 1ff9a51..8dca32c 100644
--- a/build/test_executable.mk
+++ b/build/test_executable.mk
@@ -18,4 +18,11 @@
# Replace "include $(BUILD_EXECUTABLE)" with "include $(BUILD_CTS_EXECUTABLE)"
#
+# Implicitly run this test under MTE SYNC for aarch64 binaries. This is a no-op
+# on non-MTE hardware.
+my_arch := $(TARGET_$(LOCAL_2ND_ARCH_VAR_PREFIX)ARCH)
+ifneq (,$(filter arm64,$(my_arch)))
+ LOCAL_WHOLE_STATIC_LIBRARIES += note_memtag_heap_sync
+endif
+
include $(BUILD_EXECUTABLE)
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PropertyDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PropertyDeviceInfo.java
deleted file mode 100644
index bb7f1eb..0000000
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PropertyDeviceInfo.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.compatibility.common.deviceinfo;
-
-import android.util.Log;
-
-import com.android.compatibility.common.util.DeviceInfoStore;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Scanner;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * System property info collector.
- */
-public final class PropertyDeviceInfo extends DeviceInfo {
-
- private static final String LOG_TAG = "PropertyDeviceInfo";
-
- @Override
- protected void collectDeviceInfo(DeviceInfoStore store) throws Exception {
- try {
- collectRoProperties(store);
- } catch (IOException e) {
- Log.w(LOG_TAG, "Failed to collect properties", e);
- }
- }
-
- private void collectRoProperties(DeviceInfoStore store) throws IOException {
- store.startArray("ro_property");
- Pattern pattern = Pattern.compile("\\[(ro.+)\\]: \\[(.+)\\]");
- Scanner scanner = null;
- try {
- Process getprop = new ProcessBuilder("getprop").start();
- scanner = new Scanner(getprop.getInputStream());
- while (scanner.hasNextLine()) {
- String line = scanner.nextLine();
- Matcher matcher = pattern.matcher(line);
- if (matcher.matches()) {
- String name = matcher.group(1);
- String value = matcher.group(2);
-
- store.startGroup();
- store.addResult("name", name);
- store.addResult("value", value);
- store.endGroup();
- }
- }
- } finally {
- store.endArray();
- if (scanner != null) {
- scanner.close();
- }
- }
- }
-}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/VintfDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/VintfDeviceInfo.java
index 1fb9049..8869c87 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/VintfDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/VintfDeviceInfo.java
@@ -47,6 +47,7 @@
store.addResult("hardware_id", VintfRuntimeInfo.getHardwareId());
store.addResult("kernel_version", VintfRuntimeInfo.getKernelVersion());
store.addResult("sepolicy_version", VintfObject.getSepolicyVersion());
+ store.addResult("platform_sepolicy_version", VintfObject.getPlatformSepolicyVersion());
String[] hals = VintfObject.getHalNamesAndVersions();
store.addListResult("hals", hals == null
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
index c5933a7..e7ebfba 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
@@ -16,10 +16,7 @@
package com.android.compatibility.common.util;
-import static org.junit.Assert.assertNotEquals;
-
import android.os.Build;
-import android.os.SystemProperties;
import androidx.test.InstrumentationRegistry;
@@ -44,7 +41,8 @@
private static final String BUILD_TYPE_PROPERTY = "ro.build.type";
private static final String MANUFACTURER_PROPERTY = "ro.product.manufacturer";
private static final String TAG_DEV_KEYS = "dev-keys";
- private static final String VENDOR_SDK_VERSION = "ro.vendor.build.version.sdk";
+ private static final String VENDOR_API_LEVEL = "ro.board.api_level";
+ private static final String VENDOR_FIRST_API_LEVEL = "ro.board.first_api_level";
private static final String VNDK_VERSION = "ro.vndk.version";
public static final String GOOGLE_SETTINGS_QUERY =
@@ -53,6 +51,9 @@
/** Value to be returned by getPropertyInt() if property is not found */
public static int INT_VALUE_IF_UNSET = -1;
+ /** API level for current in development */
+ public static final int API_LEVEL_CURRENT = 10000;
+
/** Returns whether the device build is a user build */
public static boolean isUserBuild() {
return propertyEquals(BUILD_TYPE_PROPERTY, "user");
@@ -79,7 +80,48 @@
}
/**
- * Return whether the VNDK version of the vendor partiton is newer than the given API level.
+ * Return the API level of the vendor partition. It will read the following properties in order
+ * and returns the value of the first defined property. If none of them are defined, or the
+ * value is a VERSION CODENAME, returns the current API level which is defined in
+ * API_LEVEL_CURRENT.
+ *
+ * <ul>
+ * <li> ro.board.api_level
+ * <li> ro.board.first_api_level
+ * <li> ro.vndk.version
+ * </ul>
+ */
+ public static int getVendorApiLevel() {
+ String[] vendorApiLevelProps = {
+ // Use the properties in order.
+ VENDOR_API_LEVEL, VENDOR_FIRST_API_LEVEL, VNDK_VERSION,
+ };
+ for (String prop : vendorApiLevelProps) {
+ int apiLevel = getPropertyInt(prop);
+ if (apiLevel != INT_VALUE_IF_UNSET) {
+ return apiLevel;
+ }
+ }
+ return API_LEVEL_CURRENT;
+ }
+
+ /**
+ * Return whether the API level of the vendor partition is newer than the given API level.
+ */
+ public static boolean isVendorApiLevelNewerThan(int apiLevel) {
+ return getVendorApiLevel() > apiLevel;
+ }
+
+ /**
+ * Return whether the API level of the vendor partition is same or newer than the
+ * given API level.
+ */
+ public static boolean isVendorApiLevelAtLeast(int apiLevel) {
+ return getVendorApiLevel() >= apiLevel;
+ }
+
+ /**
+ * Return whether the VNDK version of the vendor partition is newer than the given API level.
* If the property is set to non-integer value, this means the vendor partition is using
* current API level and true is returned.
*/
@@ -92,7 +134,7 @@
}
/**
- * Return whether the VNDK version of the vendor partiton is same or newer than the
+ * Return whether the VNDK version of the vendor partition is same or newer than the
* given API level.
* If the property is set to non-integer value, this means the vendor partition is using
* current API level and true is returned.
@@ -106,33 +148,6 @@
}
/**
- * Return whether the SDK version of the vendor partiton is newer than the given API level.
- */
- public static boolean isVendorApiLevelNewerThan(int apiLevel) {
- int vendorSdkVersion = SystemProperties.getInt(VENDOR_SDK_VERSION, 0);
- // Run previous action when failed to get ro.vendor.build.version.sdk
- // b/166800127 for details
- if (vendorSdkVersion == 0) {
- return isVndkApiLevelNewerThan(apiLevel);
- }
- return vendorSdkVersion > apiLevel;
- }
-
- /**
- * Return whether the SDK version of the vendor partiton is same or newer than the
- * given API level.
- */
- public static boolean isVendorApiLevelAtLeast(int apiLevel) {
- int vendorSdkVersion = SystemProperties.getInt(VENDOR_SDK_VERSION, 0);
- // Run previous action when failed to get ro.vendor.build.version.sdk
- // b/166800127 for details
- if (vendorSdkVersion == 0) {
- return isVndkApiLevelAtLeast(apiLevel);
- }
- return vendorSdkVersion >= apiLevel;
- }
-
- /**
* Return the manufacturer of this product. If unset, return null.
*/
public static String getManufacturer() {
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java
index c2e4224..6bf9cf3 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java
@@ -66,7 +66,9 @@
if (view == null) {
UiScrollable scrollable = new UiScrollable(new UiSelector().scrollable(true));
- scrollable.setSwipeDeadZonePercentage(0.25);
+ if (!FeatureUtil.isWatch()) {
+ scrollable.setSwipeDeadZonePercentage(0.25);
+ }
if (scrollable.exists()) {
if (isAtEnd) {
if (wasScrolledUpAlready) {
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/UiccUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/UiccUtil.java
new file mode 100644
index 0000000..69b59e8
--- /dev/null
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/UiccUtil.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import android.Manifest;
+import android.telephony.TelephonyManager;
+
+import androidx.annotation.StringDef;
+import androidx.test.InstrumentationRegistry;
+
+import java.util.List;
+
+/** Utility class for common UICC- and SIM-related operations. */
+public final class UiccUtil {
+ /** The hashes of all supported CTS UICC test keys and their corresponding specification. */
+ @StringDef({UiccCertificate.CTS_UICC_LEGACY, UiccCertificate.CTS_UICC_2021})
+ public @interface UiccCertificate {
+
+ /**
+ * Indicates compliance with the "legacy" CTS UICC specification (prior to 2021).
+ *
+ * <p>Deprecated as of 2021, support to be removed in 2022.
+ *
+ * <p>Corresponding certificate: {@code aosp-testkey}.
+ */
+ String CTS_UICC_LEGACY = "61ED377E85D386A8DFEE6B864BD85B0BFAA5AF81";
+
+ /**
+ * Indicates compliance with the 2021 CTS UICC specification.
+ *
+ * <p>Strongly recommended as of 2021, required as of 2022.
+ *
+ * <p>Corresponding certificate: {@code cts-uicc-2021-testkey}.
+ */
+ String CTS_UICC_2021 = "CE7B2B47AE2B7552C8F92CC29124279883041FB623A5F194A82C9BF15D492AA0";
+ }
+
+ /**
+ * A simple check for use with {@link org.junit.Assume#assumeTrue}. Checks the carrier privilege
+ * certificates stored on the SIM and returns {@code true} if {@code requiredCert} is present.
+ *
+ * <p>Can be used either in the {@code #setUp} method if an entire class requires a particular
+ * UICC, or at the top of a specific {@code @Test} method.
+ *
+ * <p>If we had JUnit 5, we could create a much cooler {@code @RequiresUiccCertificate}
+ * annotation using {@code ExtendWith} and {@code ExecutionCondition}, but that isn't available
+ * to us yet.
+ */
+ public static boolean uiccHasCertificate(@UiccCertificate String requiredCert) {
+ TelephonyManager tm =
+ InstrumentationRegistry.getInstrumentation()
+ .getTargetContext()
+ .getSystemService(TelephonyManager.class);
+ List<String> uiccCerts =
+ ShellIdentityUtils.invokeMethodWithShellPermissions(
+ tm,
+ TelephonyManager::getCertsFromCarrierPrivilegeAccessRules,
+ Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+ return uiccCerts == null ? false : uiccCerts.contains(requiredCert);
+ }
+}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/WindowUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/WindowUtil.java
new file mode 100644
index 0000000..4093c84
--- /dev/null
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/WindowUtil.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.compatibility.common.util;
+
+import android.app.Activity;
+import android.view.Window;
+
+public class WindowUtil {
+ /**
+ * The timeout in milliseconds to wait for window focus in
+ * {@link #waitForFocus(Window)} and {@link #waitForFocus(Activity)}.
+ */
+ public static final long WINDOW_FOCUS_TIMEOUT_MILLIS = 10_000L;
+
+ /**
+ * Waits until {@code activity}'s main window has focus, timing out after
+ * {@link #WINDOW_FOCUS_TIMEOUT_MILLIS}.
+ * @param activity The Activity whose main window should gain focus.
+ */
+ public static void waitForFocus(Activity activity) {
+ PollingCheck.waitFor(WINDOW_FOCUS_TIMEOUT_MILLIS,
+ activity::hasWindowFocus);
+ }
+
+ /**
+ * Waits until {@code window} has focus, timing out after {@link #WINDOW_FOCUS_TIMEOUT_MILLIS}.
+ * @param window The Window that should gain focus.
+ */
+ public static void waitForFocus(Window window) {
+ PollingCheck.waitFor(WINDOW_FOCUS_TIMEOUT_MILLIS,
+ window.getDecorView()::hasWindowFocus);
+ }
+}
diff --git a/hostsidetests/apex/src/android/apex/cts/ApexTest.java b/hostsidetests/apex/src/android/apex/cts/ApexTest.java
index 6652ef02..91920ad 100644
--- a/hostsidetests/apex/src/android/apex/cts/ApexTest.java
+++ b/hostsidetests/apex/src/android/apex/cts/ApexTest.java
@@ -37,14 +37,14 @@
private boolean isGSI() throws Exception {
String systemProduct = getDevice().getProperty("ro.product.system_ext.name");
return (null != systemProduct)
- && (systemProduct.equals("aosp_arm")
+ && (systemProduct.equals("gsi_arm")
+ || systemProduct.equals("gsi_arm64")
+ || systemProduct.equals("gsi_x86")
+ || systemProduct.equals("gsi_x86_64")
+ || systemProduct.equals("aosp_arm")
|| systemProduct.equals("aosp_arm64")
|| systemProduct.equals("aosp_x86")
|| systemProduct.equals("aosp_x86_64")
- || systemProduct.equals("aosp_arm_ab") // _ab for Legacy GSI
- || systemProduct.equals("aosp_arm64_ab")
- || systemProduct.equals("aosp_x86_ab")
- || systemProduct.equals("aosp_x86_64_ab")
|| systemProduct.equals("aosp_tv_arm")
|| systemProduct.equals("aosp_tv_arm64"));
}
diff --git a/hostsidetests/appcompat/compatchanges/app/Android.bp b/hostsidetests/appcompat/compatchanges/app/Android.bp
index 9dde881..a54e141 100644
--- a/hostsidetests/appcompat/compatchanges/app/Android.bp
+++ b/hostsidetests/appcompat/compatchanges/app/Android.bp
@@ -28,6 +28,7 @@
],
static_libs: [
"ctstestrunner-axt",
+ "testng",
"truth-prebuilt",
],
diff --git a/hostsidetests/appcompat/compatchanges/app/src/com/android/cts/appcompat/compatchanges/CompatChangesTest.java b/hostsidetests/appcompat/compatchanges/app/src/com/android/cts/appcompat/compatchanges/CompatChangesTest.java
index 27cef40..16214ce 100644
--- a/hostsidetests/appcompat/compatchanges/app/src/com/android/cts/appcompat/compatchanges/CompatChangesTest.java
+++ b/hostsidetests/appcompat/compatchanges/app/src/com/android/cts/appcompat/compatchanges/CompatChangesTest.java
@@ -17,9 +17,11 @@
package com.android.cts.appcompat.compatchanges;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertThrows;
import android.Manifest;
import android.app.compat.CompatChanges;
+import android.app.compat.PackageOverride;
import android.content.Context;
import android.os.Process;
@@ -30,7 +32,8 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
+
+import java.util.Collections;
/**
* Tests for the {@link android.app.compat.CompatChanges} SystemApi.
@@ -44,11 +47,16 @@
@RunWith(AndroidJUnit4.class)
public final class CompatChangesTest {
private static final long CTS_SYSTEM_API_CHANGEID = 149391281;
+ private static final long CTS_SYSTEM_API_OVERRIDABLE_CHANGEID = 174043039;
+
+ private static final String OVERRIDE_PACKAGE = "com.android.cts.appcompat.preinstalloverride";
+
@Before
public void setUp() {
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.adoptShellPermissionIdentity(Manifest.permission.LOG_COMPAT_CHANGE,
- Manifest.permission.READ_COMPAT_CHANGE_CONFIG);
+ Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
+ Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD);
}
@After
@@ -95,4 +103,88 @@
public void isChangeEnabledUid_changeDisabled() {
assertThat(CompatChanges.isChangeEnabled(CTS_SYSTEM_API_CHANGEID, Process.myUid())).isFalse();
}
+
+ @Test
+ public void putPackageOverrides_securityExceptionForNonOverridableChangeId() {
+ SecurityException e = assertThrows(SecurityException.class,
+ () -> CompatChanges.putPackageOverrides(OVERRIDE_PACKAGE,
+ Collections.singletonMap(CTS_SYSTEM_API_CHANGEID,
+ new PackageOverride.Builder().setEnabled(true).build())));
+ assertThat(e).hasMessageThat().contains("marked as Overridable");
+ }
+
+ @Test
+ public void putPackageOverrides_success() {
+ CompatChanges.putPackageOverrides(OVERRIDE_PACKAGE,
+ Collections.singletonMap(CTS_SYSTEM_API_OVERRIDABLE_CHANGEID,
+ new PackageOverride.Builder().setEnabled(true).build()));
+ }
+
+ @Test
+ public void putPackageOverrides_fromVersion2() {
+ CompatChanges.putPackageOverrides(OVERRIDE_PACKAGE,
+ Collections.singletonMap(CTS_SYSTEM_API_OVERRIDABLE_CHANGEID,
+ new PackageOverride.Builder().setMinVersionCode(2).setEnabled(true).build()));
+ }
+
+ @Test
+ public void putPackageOverrides_untilVersion1() {
+ CompatChanges.putPackageOverrides(OVERRIDE_PACKAGE,
+ Collections.singletonMap(CTS_SYSTEM_API_OVERRIDABLE_CHANGEID,
+ new PackageOverride.Builder().setMaxVersionCode(1).setEnabled(true).build()));
+ }
+
+ @Test
+ public void putPackageOverrides_securityExceptionForNotHoldingPermission() {
+ // Adopt the normal override permission that doesn't allow to clear overrides on release builds
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
+ Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG);
+
+ SecurityException e = assertThrows(SecurityException.class,
+ () -> CompatChanges.putPackageOverrides(OVERRIDE_PACKAGE,
+ Collections.singletonMap(CTS_SYSTEM_API_OVERRIDABLE_CHANGEID,
+ new PackageOverride.Builder().setEnabled(true).build())));
+ assertThat(e).hasMessageThat().contains("Cannot override compat change");
+ }
+
+ @Test
+ public void removePackageOverrides_securityExceptionForNonOverridableChangeId() {
+ SecurityException e = assertThrows(SecurityException.class,
+ () -> CompatChanges.removePackageOverrides(OVERRIDE_PACKAGE,
+ Collections.singleton(CTS_SYSTEM_API_CHANGEID)));
+ assertThat(e).hasMessageThat().contains("marked as Overridable");
+ }
+
+ @Test
+ public void removePackageOverrides_doesNothingIfOverrideNotPresent() {
+ CompatChanges.removePackageOverrides(OVERRIDE_PACKAGE,
+ Collections.singleton(CTS_SYSTEM_API_OVERRIDABLE_CHANGEID));
+ }
+
+ @Test
+ public void removePackageOverrides_overridePresentSuccess() {
+ CompatChanges.putPackageOverrides(OVERRIDE_PACKAGE,
+ Collections.singletonMap(CTS_SYSTEM_API_OVERRIDABLE_CHANGEID,
+ new PackageOverride.Builder().setEnabled(true).build()));
+ CompatChanges.removePackageOverrides(OVERRIDE_PACKAGE,
+ Collections.singleton(CTS_SYSTEM_API_OVERRIDABLE_CHANGEID));
+ }
+
+ @Test
+ public void removePackageOverrides_securityExceptionForNotHoldingPermission() {
+ CompatChanges.putPackageOverrides(OVERRIDE_PACKAGE,
+ Collections.singletonMap(CTS_SYSTEM_API_OVERRIDABLE_CHANGEID,
+ new PackageOverride.Builder().setEnabled(true).build()));
+
+ // Adopt the normal override permission that doesn't allow to clear overrides on release builds
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
+ Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG);
+
+ SecurityException e = assertThrows(SecurityException.class,
+ () -> CompatChanges.removePackageOverrides(OVERRIDE_PACKAGE,
+ Collections.singleton(CTS_SYSTEM_API_OVERRIDABLE_CHANGEID)));
+ assertThat(e).hasMessageThat().contains("Cannot override compat change");
+ }
}
diff --git a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesOverrideOnReleaseBuildTest.java b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesOverrideOnReleaseBuildTest.java
new file mode 100644
index 0000000..70ba008
--- /dev/null
+++ b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesOverrideOnReleaseBuildTest.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.appcompat;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.compat.cts.Change;
+import android.compat.cts.CompatChangeGatingTestCase;
+
+import com.google.common.collect.ImmutableSet;
+
+public class CompatChangesOverrideOnReleaseBuildTest extends CompatChangeGatingTestCase {
+ private static final String TEST_APK = "CtsHostsideCompatChangeTestsApp.apk";
+ private static final String TEST_PKG = "com.android.cts.appcompat.compatchanges";
+
+ private static final String OVERRIDE_PKG = "com.android.cts.appcompat.preinstalloverride";
+
+ private static final long CTS_CHANGE_ID = 149391281L;
+ private static final long CTS_OVERRIDABLE_CHANGE_ID = 174043039L;
+
+ @Override
+ protected void setUp() throws Exception {
+ installPackage(TEST_APK, true);
+ runCommand("am compat reset-all " + OVERRIDE_PKG);
+ runCommand("settings put global force_non_debuggable_final_build_for_compat 1");
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ runCommand("am compat reset-all " + OVERRIDE_PKG);
+ uninstallPackage(TEST_PKG, true);
+ uninstallPackage(OVERRIDE_PKG, false);
+ runCommand("settings put global force_non_debuggable_final_build_for_compat 0");
+ }
+
+ public void testPutPackageOverridesSecurityExceptionNonOverridableChangeId() throws Exception {
+ installPackage("appcompat_preinstall_override_versioncode1_release.apk", false);
+
+ runDeviceCompatTest(TEST_PKG, ".CompatChangesTest",
+ "putPackageOverrides_securityExceptionForNonOverridableChangeId",
+ /*enabledChanges*/ImmutableSet.of(),
+ /*disabledChanges*/ ImmutableSet.of());
+
+ Change ctsChange = getOnDeviceChangeIdConfig(CTS_OVERRIDABLE_CHANGE_ID);
+ assertWithMessage("CTS specific change %s not found on device", CTS_OVERRIDABLE_CHANGE_ID)
+ .that(ctsChange).isNotNull();
+ assertThat(ctsChange.hasRawOverrides).isFalse();
+ assertThat(ctsChange.hasOverrides).isFalse();
+ }
+
+ public void testPutPackageOverridesSecurityExceptionMissingPermission() throws Exception {
+ installPackage("appcompat_preinstall_override_versioncode1_release.apk", false);
+
+ runDeviceCompatTest(TEST_PKG, ".CompatChangesTest",
+ "putPackageOverrides_securityExceptionForNotHoldingPermission",
+ /*enabledChanges*/ImmutableSet.of(),
+ /*disabledChanges*/ ImmutableSet.of());
+
+ Change ctsChange = getOnDeviceChangeIdConfig(CTS_OVERRIDABLE_CHANGE_ID);
+ assertWithMessage("CTS specific change %s not found on device", CTS_OVERRIDABLE_CHANGE_ID)
+ .that(ctsChange).isNotNull();
+ assertThat(ctsChange.hasRawOverrides).isFalse();
+ assertThat(ctsChange.hasOverrides).isFalse();
+ }
+
+ public void testPutPackageOverridesForAllVersions() throws Exception {
+ installPackage("appcompat_preinstall_override_versioncode1_release.apk", false);
+
+ runDeviceCompatTest(TEST_PKG, ".CompatChangesTest",
+ "putPackageOverrides_success",
+ /*enabledChanges*/ImmutableSet.of(),
+ /*disabledChanges*/ ImmutableSet.of());
+
+ Change ctsChange = getOnDeviceChangeIdConfig(CTS_OVERRIDABLE_CHANGE_ID);
+ assertWithMessage("CTS specific change %s not found on device", CTS_OVERRIDABLE_CHANGE_ID)
+ .that(ctsChange).isNotNull();
+ assertThat(ctsChange.hasRawOverrides).isTrue();
+ assertThat(ctsChange.rawOverrideStr).isEqualTo("{" + OVERRIDE_PKG + "=true}");
+ assertThat(ctsChange.hasOverrides).isTrue();
+ assertThat(ctsChange.overridesStr).isEqualTo("{" + OVERRIDE_PKG + "=true}");
+
+ // Now update to newer app version and the override should be applied
+ installPackage("appcompat_preinstall_override_versioncode2_release.apk", false);
+
+ ctsChange = getOnDeviceChangeIdConfig(CTS_OVERRIDABLE_CHANGE_ID);
+ assertWithMessage("CTS specific change %s not found on device", CTS_OVERRIDABLE_CHANGE_ID)
+ .that(ctsChange).isNotNull();
+ assertThat(ctsChange.hasRawOverrides).isTrue();
+ assertThat(ctsChange.rawOverrideStr).isEqualTo("{" + OVERRIDE_PKG + "=true}");
+ assertThat(ctsChange.hasOverrides).isTrue();
+ assertThat(ctsChange.overridesStr).isEqualTo("{" + OVERRIDE_PKG + "=true}");
+ }
+
+ public void testPutPackageOverridesForNewerVersion() throws Exception {
+ installPackage("appcompat_preinstall_override_versioncode1_release.apk", false);
+
+ runDeviceCompatTest(TEST_PKG, ".CompatChangesTest",
+ "putPackageOverrides_fromVersion2",
+ /*enabledChanges*/ImmutableSet.of(),
+ /*disabledChanges*/ ImmutableSet.of());
+
+ Change ctsChange = getOnDeviceChangeIdConfig(CTS_OVERRIDABLE_CHANGE_ID);
+ assertWithMessage("CTS specific change %s not found on device", CTS_OVERRIDABLE_CHANGE_ID)
+ .that(ctsChange).isNotNull();
+ assertThat(ctsChange.hasRawOverrides).isTrue();
+ assertThat(ctsChange.rawOverrideStr).isEqualTo("{" + OVERRIDE_PKG
+ + "=[2,9223372036854775807,true]}");
+ assertThat(ctsChange.hasOverrides).isFalse();
+
+ // Now update to newer app version and the override should be applied
+ installPackage("appcompat_preinstall_override_versioncode2_release.apk", false);
+
+ ctsChange = getOnDeviceChangeIdConfig(CTS_OVERRIDABLE_CHANGE_ID);
+ assertWithMessage("CTS specific change %s not found on device", CTS_OVERRIDABLE_CHANGE_ID)
+ .that(ctsChange).isNotNull();
+ assertThat(ctsChange.hasRawOverrides).isTrue();
+ assertThat(ctsChange.rawOverrideStr).isEqualTo("{" + OVERRIDE_PKG
+ + "=[2,9223372036854775807,true]}");
+ assertThat(ctsChange.hasOverrides).isTrue();
+ assertThat(ctsChange.overridesStr).isEqualTo("{" + OVERRIDE_PKG + "=true}");
+ }
+
+ public void testPutPackageOverridesForOlderVersion() throws Exception {
+ installPackage("appcompat_preinstall_override_versioncode1_release.apk", false);
+
+ runDeviceCompatTest(TEST_PKG, ".CompatChangesTest",
+ "putPackageOverrides_untilVersion1",
+ /*enabledChanges*/ImmutableSet.of(),
+ /*disabledChanges*/ ImmutableSet.of());
+
+ Change ctsChange = getOnDeviceChangeIdConfig(CTS_OVERRIDABLE_CHANGE_ID);
+ assertWithMessage("CTS specific change %s not found on device", CTS_OVERRIDABLE_CHANGE_ID)
+ .that(ctsChange).isNotNull();
+ assertThat(ctsChange.hasRawOverrides).isTrue();
+ assertThat(ctsChange.rawOverrideStr).isEqualTo("{" + OVERRIDE_PKG
+ + "=[-9223372036854775808,1,true]}");
+ assertThat(ctsChange.hasOverrides).isTrue();
+ assertThat(ctsChange.overridesStr).isEqualTo("{" + OVERRIDE_PKG + "=true}");
+
+ // Now update to newer app version and the override should no longer be applied
+ installPackage("appcompat_preinstall_override_versioncode2_release.apk", false);
+ ctsChange = getOnDeviceChangeIdConfig(CTS_OVERRIDABLE_CHANGE_ID);
+ assertWithMessage("CTS specific change %s not found on device", CTS_OVERRIDABLE_CHANGE_ID)
+ .that(ctsChange).isNotNull();
+ assertThat(ctsChange.hasRawOverrides).isTrue();
+ assertThat(ctsChange.rawOverrideStr).isEqualTo("{" + OVERRIDE_PKG
+ + "=[-9223372036854775808,1,true]}");
+ assertThat(ctsChange.hasOverrides).isFalse();
+ }
+
+ public void testRemovePackageOverridesSecurityExceptionNonOverridableChangeId()
+ throws Exception {
+ installPackage("appcompat_preinstall_override_versioncode1_release.apk", false);
+
+ runDeviceCompatTest(TEST_PKG, ".CompatChangesTest",
+ "removePackageOverrides_securityExceptionForNonOverridableChangeId",
+ /*enabledChanges*/ImmutableSet.of(),
+ /*disabledChanges*/ ImmutableSet.of());
+ }
+
+ public void testRemovePackageOverridesSecurityExceptionMissingPermission() throws Exception {
+ installPackage("appcompat_preinstall_override_versioncode1_release.apk", false);
+
+ runDeviceCompatTest(TEST_PKG, ".CompatChangesTest",
+ "removePackageOverrides_securityExceptionForNotHoldingPermission",
+ /*enabledChanges*/ImmutableSet.of(),
+ /*disabledChanges*/ ImmutableSet.of());
+
+ Change ctsChange = getOnDeviceChangeIdConfig(CTS_OVERRIDABLE_CHANGE_ID);
+ assertWithMessage("CTS specific change %s not found on device", CTS_OVERRIDABLE_CHANGE_ID)
+ .that(ctsChange).isNotNull();
+ assertThat(ctsChange.hasRawOverrides).isTrue();
+ assertThat(ctsChange.rawOverrideStr).isEqualTo("{" + OVERRIDE_PKG + "=true}");
+ }
+
+ public void testRemovePackageOverridesWhenOverrideNotPresent() throws Exception {
+ installPackage("appcompat_preinstall_override_versioncode1_release.apk", false);
+
+ runDeviceCompatTest(TEST_PKG, ".CompatChangesTest",
+ "removePackageOverrides_doesNothingIfOverrideNotPresent",
+ /*enabledChanges*/ImmutableSet.of(),
+ /*disabledChanges*/ ImmutableSet.of());
+
+ Change ctsChange = getOnDeviceChangeIdConfig(CTS_OVERRIDABLE_CHANGE_ID);
+ assertWithMessage("CTS specific change %s not found on device", CTS_OVERRIDABLE_CHANGE_ID)
+ .that(ctsChange).isNotNull();
+ assertThat(ctsChange.hasRawOverrides).isFalse();
+ assertThat(ctsChange.hasOverrides).isFalse();
+ }
+
+ public void testRemovePackageOverridesWhenOverridePresent() throws Exception {
+ installPackage("appcompat_preinstall_override_versioncode1_release.apk", false);
+
+ runDeviceCompatTest(TEST_PKG, ".CompatChangesTest",
+ "removePackageOverrides_overridePresentSuccess",
+ /*enabledChanges*/ImmutableSet.of(),
+ /*disabledChanges*/ ImmutableSet.of());
+
+ Change ctsChange = getOnDeviceChangeIdConfig(CTS_OVERRIDABLE_CHANGE_ID);
+ assertWithMessage("CTS specific change %s not found on device", CTS_OVERRIDABLE_CHANGE_ID)
+ .that(ctsChange).isNotNull();
+ assertThat(ctsChange.hasRawOverrides).isFalse();
+ assertThat(ctsChange.hasOverrides).isFalse();
+ }
+}
diff --git a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesPreInstallOverrideTest.java b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesPreInstallOverrideTest.java
index bf5e4d5..e3d3d80 100644
--- a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesPreInstallOverrideTest.java
+++ b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesPreInstallOverrideTest.java
@@ -130,12 +130,6 @@
}
private Change getCtsChange() throws Exception {
- List<Change> allChanges = getOnDeviceCompatConfig();
- for (Change change : allChanges) {
- if (change.changeId == CTS_CHANGE_ID) {
- return change;
- }
- }
- return null;
+ return getOnDeviceChangeIdConfig(CTS_CHANGE_ID);
}
}
diff --git a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
index ef53750..5d4b2a1 100644
--- a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
+++ b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesValidConfigTest.java
@@ -17,6 +17,7 @@
package com.android.cts.appcompat;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import android.compat.cts.Change;
import android.compat.cts.CompatChangeGatingTestCase;
@@ -32,8 +33,6 @@
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public final class CompatChangesValidConfigTest extends CompatChangeGatingTestCase {
@@ -43,13 +42,30 @@
"ALLOW_TEST_API_ACCESS"
);
+ private static final Set<String> OVERRIDABLE_CHANGES = ImmutableSet.of(
+ "CTS_SYSTEM_API_OVERRIDABLE_CHANGEID"
+ );
+
/**
* Check that there are no overrides.
*/
public void testNoOverrides() throws Exception {
for (Change c : getOnDeviceCompatConfig()) {
- if (!OVERRIDES_ALLOWLIST.contains(c.changeName)) {
- assertThat(c.hasOverrides).isFalse();
+ if (!OVERRIDES_ALLOWLIST.contains(c.changeName) && !c.overridable) {
+ assertWithMessage("Change should not have overrides: " + c)
+ .that(c.hasOverrides).isFalse();
+ }
+ }
+ }
+
+ /**
+ * Check that only approved changes are overridable.
+ */
+ public void testOnlyAllowedlistedChangesAreOverridable() throws Exception {
+ for (Change c : getOnDeviceCompatConfig()) {
+ if (c.overridable) {
+ assertWithMessage("Please contact platform-compat-eng@google.com for approval")
+ .that(OVERRIDABLE_CHANGES).contains(c.changeName);
}
}
}
diff --git a/hostsidetests/appcompat/host/lib/src/android/compat/cts/Change.java b/hostsidetests/appcompat/host/lib/src/android/compat/cts/Change.java
index 8e6c8e7..105e6ca 100644
--- a/hostsidetests/appcompat/host/lib/src/android/compat/cts/Change.java
+++ b/hostsidetests/appcompat/host/lib/src/android/compat/cts/Change.java
@@ -30,28 +30,30 @@
+ "(; (?<disabled>disabled))?"
+ "(; (?<loggingOnly>loggingOnly))?"
+ "(; packageOverrides=(?<overrides>[^\\);]+))?"
- + "(; rawOverrides=(?<rawOverrides>[^\\)]+))?"
+ + "(; rawOverrides=(?<rawOverrides>[^\\);]+))?"
+ + "(; (?<overridable>overridable))?"
+ "\\)");
public long changeId;
public String changeName;
public int sinceSdk;
public boolean disabled;
public boolean loggingOnly;
+ public boolean overridable;
public boolean hasRawOverrides;
public boolean hasOverrides;
-
public String rawOverrideStr;
public String overridesStr;
private Change(long changeId, String changeName, int sinceSdk,
- boolean disabled, boolean loggingOnly, boolean hasRawOverrides,
- boolean hasOverrides, String rawOverrideStr,
- String overridesStr) {
+ boolean disabled, boolean loggingOnly, boolean overridable,
+ boolean hasRawOverrides, boolean hasOverrides,
+ String rawOverrideStr, String overridesStr) {
this.changeId = changeId;
this.changeName = changeName;
this.sinceSdk = sinceSdk;
this.disabled = disabled;
this.loggingOnly = loggingOnly;
+ this.overridable = overridable;
this.hasRawOverrides = hasRawOverrides;
this.hasOverrides = hasOverrides;
this.rawOverrideStr = rawOverrideStr;
@@ -64,9 +66,9 @@
int sinceSdk = -1;
boolean disabled = false;
boolean loggingOnly = false;
+ boolean overridable = false;
boolean hasRawOverrides = false;
boolean hasOverrides = false;
-
String rawOverridesStr = null;
String overridesStr = null;
@@ -103,7 +105,10 @@
hasRawOverrides = true;
rawOverridesStr = matcher.group("rawOverrides");
}
- return new Change(changeId, changeName, sinceSdk, disabled, loggingOnly,
+ if (matcher.group("overridable") != null) {
+ overridable = true;
+ }
+ return new Change(changeId, changeName, sinceSdk, disabled, loggingOnly, overridable,
hasRawOverrides, hasOverrides, rawOverridesStr,
overridesStr);
}
@@ -132,8 +137,13 @@
if (element.hasAttribute("loggingOnly")) {
loggingOnly = true;
}
- return new Change(changeId, changeName, sinceSdk, disabled, loggingOnly, false, false,
- null, null);
+ boolean overridable = false;
+ if (element.hasAttribute("overridable")) {
+ overridable = true;
+ }
+ return new Change(changeId, changeName, sinceSdk, disabled, loggingOnly, overridable,
+ /* hasRawOverrides= */ false, /* hasOverrides= */ false,
+ /* rawOverridesStr= */ null, /* overridesStr= */null);
}
@Override
@@ -155,8 +165,7 @@
&& this.sinceSdk == that.sinceSdk
&& this.disabled == that.disabled
&& this.loggingOnly == that.loggingOnly
- && this.hasRawOverrides == that.hasRawOverrides
- && this.hasOverrides == that.hasOverrides;
+ && this.overridable == that.overridable;
}
@Override
@@ -172,17 +181,20 @@
if (disabled) {
sb.append("; disabled");
}
- if (hasRawOverrides) {
- sb.append("; rawOverrides={");
- sb.append(rawOverrideStr);
- sb.append("}");
- }
if (hasOverrides) {
sb.append("; packageOverrides={");
sb.append(overridesStr);
sb.append("}");
}
+ if (hasRawOverrides) {
+ sb.append("; rawOverrides={");
+ sb.append(rawOverrideStr);
+ sb.append("}");
+ }
+ if (overridable) {
+ sb.append("; overridable");
+ }
sb.append(")");
return sb.toString();
}
-}
\ No newline at end of file
+}
diff --git a/hostsidetests/appcompat/host/lib/src/android/compat/cts/CompatChangeGatingTestCase.java b/hostsidetests/appcompat/host/lib/src/android/compat/cts/CompatChangeGatingTestCase.java
index 84300a2..10803dd 100644
--- a/hostsidetests/appcompat/host/lib/src/android/compat/cts/CompatChangeGatingTestCase.java
+++ b/hostsidetests/appcompat/host/lib/src/android/compat/cts/CompatChangeGatingTestCase.java
@@ -367,4 +367,13 @@
.collect(Collectors.toList());
}
+ protected Change getOnDeviceChangeIdConfig(long changeId) throws Exception {
+ List<Change> changes = getOnDeviceCompatConfig();
+ for (Change change : changes) {
+ if (change.changeId == changeId) {
+ return change;
+ }
+ }
+ return null;
+ }
}
diff --git a/hostsidetests/appcompat/strictjavapackages/Android.bp b/hostsidetests/appcompat/strictjavapackages/Android.bp
index 0f922102..fcb20e8 100644
--- a/hostsidetests/appcompat/strictjavapackages/Android.bp
+++ b/hostsidetests/appcompat/strictjavapackages/Android.bp
@@ -26,6 +26,7 @@
"compatibility-host-util",
],
static_libs: [
+ "compat-classpaths-testing",
"dexlib2-no-guava-no-cli",
],
// tag this module as a cts test artifact
diff --git a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
index e73f31a..f170cab 100644
--- a/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
+++ b/hostsidetests/appcompat/strictjavapackages/src/android/compat/sjp/cts/StrictJavaPackagesTest.java
@@ -16,200 +16,184 @@
package android.compat.sjp.cts;
+import static android.compat.testing.Classpaths.ClasspathType.BOOTCLASSPATH;
+import static android.compat.testing.Classpaths.ClasspathType.SYSTEMSERVERCLASSPATH;
+
import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
+
import static org.junit.Assume.assumeTrue;
-import static java.util.stream.Collectors.toSet;
+
+import android.compat.testing.Classpaths;
import com.android.compatibility.common.util.ApiLevelUtil;
-
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
-import com.google.common.collect.Sets;
+import com.google.common.collect.Multimaps;
-import java.io.File;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Set;
-
-import org.jf.dexlib2.DexFileFactory;
-import org.jf.dexlib2.Opcodes;
-import org.jf.dexlib2.dexbacked.DexBackedDexFile;
-import org.jf.dexlib2.iface.DexFile;
import org.jf.dexlib2.iface.ClassDef;
-import org.jf.dexlib2.iface.MultiDexContainer;
-
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Tests for detecting no duplicate class files are present on BOOTCLASSPATH and
+ * SYSTEMSERVERCLASSPATH.
+ *
+ * <p>Duplicate class files are not safe as some of the jars on *CLASSPATH are updated outside of
+ * the main dessert release cycle; they also contribute to unnecessary disk space usage.
+ */
@RunWith(DeviceJUnit4ClassRunner.class)
-public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
- private static final long ADB_TIMEOUT_MILLIS = 10000L;
+public class StrictJavaPackagesTest extends BaseHostJUnit4Test {
+
/**
* This is the list of classes that are currently duplicated and should be addressed.
*
* <p> DO NOT ADD CLASSES TO THIS LIST!
*/
private static final Set<String> BCP_AND_SSCP_OVERLAP_BURNDOWN_LIST =
- ImmutableSet.of(
- "Landroid/annotation/CallbackExecutor;",
- "Landroid/annotation/CheckResult;",
- "Landroid/annotation/CurrentTimeMillisLong;",
- "Landroid/annotation/Hide;",
- "Landroid/annotation/IntDef;",
- "Landroid/annotation/IntRange;",
- "Landroid/annotation/LongDef;",
- "Landroid/annotation/NonNull;",
- "Landroid/annotation/Nullable;",
- "Landroid/annotation/RequiresPermission;",
- "Landroid/annotation/RequiresPermission$Read;",
- "Landroid/annotation/RequiresPermission$Write;",
- "Landroid/annotation/SdkConstant;",
- "Landroid/annotation/SdkConstant$SdkConstantType;",
- "Landroid/annotation/StringDef;",
- "Landroid/annotation/SystemApi;",
- "Landroid/annotation/SystemApi$Client;",
- "Landroid/annotation/SystemApi$Container;",
- "Landroid/annotation/SystemService;",
- "Landroid/annotation/TestApi;",
- "Landroid/annotation/WorkerThread;",
- "Landroid/gsi/AvbPublicKey;",
- "Landroid/gsi/AvbPublicKey$1;",
- "Landroid/gsi/GsiProgress;",
- "Landroid/gsi/GsiProgress$1;",
- "Landroid/gsi/IGsiService;",
- "Landroid/gsi/IGsiService$Default;",
- "Landroid/gsi/IGsiService$Stub;",
- "Landroid/gsi/IGsiService$Stub$Proxy;",
- "Landroid/gsi/IGsiServiceCallback;",
- "Landroid/gsi/IGsiServiceCallback$Default;",
- "Landroid/gsi/IGsiServiceCallback$Stub;",
- "Landroid/gsi/IGsiServiceCallback$Stub$Proxy;",
- "Landroid/gsi/IImageService;",
- "Landroid/gsi/IImageService$Default;",
- "Landroid/gsi/IImageService$Stub;",
- "Landroid/gsi/IImageService$Stub$Proxy;",
- "Landroid/gsi/IProgressCallback;",
- "Landroid/gsi/IProgressCallback$Default;",
- "Landroid/gsi/IProgressCallback$Stub;",
- "Landroid/gsi/IProgressCallback$Stub$Proxy;",
- "Landroid/gsi/MappedImage;",
- "Landroid/gsi/MappedImage$1;",
- "Landroid/hardware/contexthub/V1_0/AsyncEventType;",
- "Landroid/hardware/contexthub/V1_0/ContextHub;",
- "Landroid/hardware/contexthub/V1_0/ContextHubMsg;",
- "Landroid/hardware/contexthub/V1_0/HostEndPoint;",
- "Landroid/hardware/contexthub/V1_0/HubAppInfo;",
- "Landroid/hardware/contexthub/V1_0/HubMemoryFlag;",
- "Landroid/hardware/contexthub/V1_0/HubMemoryType;",
- "Landroid/hardware/contexthub/V1_0/IContexthub;",
- "Landroid/hardware/contexthub/V1_0/IContexthub$Proxy;",
- "Landroid/hardware/contexthub/V1_0/IContexthub$Stub;",
- "Landroid/hardware/contexthub/V1_0/IContexthubCallback;",
- "Landroid/hardware/contexthub/V1_0/IContexthubCallback$Proxy;",
- "Landroid/hardware/contexthub/V1_0/IContexthubCallback$Stub;",
- "Landroid/hardware/contexthub/V1_0/MemRange;",
- "Landroid/hardware/contexthub/V1_0/NanoAppBinary;",
- "Landroid/hardware/contexthub/V1_0/NanoAppFlags;",
- "Landroid/hardware/contexthub/V1_0/PhysicalSensor;",
- "Landroid/hardware/contexthub/V1_0/Result;",
- "Landroid/hardware/contexthub/V1_0/SensorType;",
- "Landroid/hardware/contexthub/V1_0/TransactionResult;",
- "Landroid/hardware/usb/gadget/V1_0/GadgetFunction;",
- "Landroid/hardware/usb/gadget/V1_0/IUsbGadget;",
- "Landroid/hardware/usb/gadget/V1_0/IUsbGadget$Proxy;",
- "Landroid/hardware/usb/gadget/V1_0/IUsbGadget$Stub;",
- "Landroid/hardware/usb/gadget/V1_0/IUsbGadgetCallback;",
- "Landroid/hardware/usb/gadget/V1_0/IUsbGadgetCallback$Proxy;",
- "Landroid/hardware/usb/gadget/V1_0/IUsbGadgetCallback$Stub;",
- "Landroid/hardware/usb/gadget/V1_0/Status;",
- "Landroid/os/IDumpstate;",
- "Landroid/os/IDumpstate$Default;",
- "Landroid/os/IDumpstate$Stub;",
- "Landroid/os/IDumpstate$Stub$Proxy;",
- "Landroid/os/IDumpstateListener;",
- "Landroid/os/IDumpstateListener$Default;",
- "Landroid/os/IDumpstateListener$Stub;",
- "Landroid/os/IDumpstateListener$Stub$Proxy;",
- "Landroid/os/IInstalld;",
- "Landroid/os/IInstalld$Default;",
- "Landroid/os/IInstalld$Stub;",
- "Landroid/os/IInstalld$Stub$Proxy;",
- "Landroid/os/IStoraged;",
- "Landroid/os/IStoraged$Default;",
- "Landroid/os/IStoraged$Stub;",
- "Landroid/os/IStoraged$Stub$Proxy;",
- "Landroid/os/IVold;",
- "Landroid/os/IVold$Default;",
- "Landroid/os/IVold$Stub;",
- "Landroid/os/IVold$Stub$Proxy;",
- "Landroid/os/IVoldListener;",
- "Landroid/os/IVoldListener$Default;",
- "Landroid/os/IVoldListener$Stub;",
- "Landroid/os/IVoldListener$Stub$Proxy;",
- "Landroid/os/IVoldMountCallback;",
- "Landroid/os/IVoldMountCallback$Default;",
- "Landroid/os/IVoldMountCallback$Stub;",
- "Landroid/os/IVoldMountCallback$Stub$Proxy;",
- "Landroid/os/IVoldTaskListener;",
- "Landroid/os/IVoldTaskListener$Default;",
- "Landroid/os/IVoldTaskListener$Stub;",
- "Landroid/os/IVoldTaskListener$Stub$Proxy;",
- "Landroid/os/storage/CrateMetadata;",
- "Landroid/os/storage/CrateMetadata$1;",
- "Landroid/view/LayerMetadataKey;",
- "Lcom/android/internal/annotations/GuardedBy;",
- "Lcom/android/internal/annotations/Immutable;",
- "Lcom/android/internal/annotations/VisibleForTesting;",
- "Lcom/android/internal/annotations/VisibleForTesting$Visibility;",
- // TODO(b/173649240): due to an oversight, some new overlaps slipped through in S.
- "Landroid/hardware/usb/gadget/V1_1/IUsbGadget;",
- "Landroid/hardware/usb/gadget/V1_1/IUsbGadget$Proxy;",
- "Landroid/hardware/usb/gadget/V1_1/IUsbGadget$Stub;",
- "Landroid/hardware/usb/gadget/V1_2/GadgetFunction;",
- "Landroid/hardware/usb/gadget/V1_2/IUsbGadget;",
- "Landroid/hardware/usb/gadget/V1_2/IUsbGadget$Proxy;",
- "Landroid/hardware/usb/gadget/V1_2/IUsbGadget$Stub;",
- "Landroid/hardware/usb/gadget/V1_2/IUsbGadgetCallback;",
- "Landroid/hardware/usb/gadget/V1_2/IUsbGadgetCallback$Proxy;",
- "Landroid/hardware/usb/gadget/V1_2/IUsbGadgetCallback$Stub;",
- "Landroid/hardware/usb/gadget/V1_2/UsbSpeed;",
- "Landroid/os/BlockUntrustedTouchesMode;",
- "Landroid/os/CreateAppDataArgs;",
- "Landroid/os/CreateAppDataArgs$1;",
- "Landroid/os/CreateAppDataResult;",
- "Landroid/os/CreateAppDataResult$1;",
- "Landroid/os/IInputConstants;",
- "Landroid/os/IInputConstants$Default;",
- "Landroid/os/IInputConstants$Stub;",
- "Landroid/os/IInputConstants$Stub$Proxy;",
- "Landroid/os/InputEventInjectionResult;",
- "Landroid/os/InputEventInjectionSync;",
- "Landroid/os/TouchOcclusionMode;",
- "Lcom/android/internal/protolog/common/BitmaskConversionException;",
- "Lcom/android/internal/protolog/common/InvalidFormatStringException;",
- "Lcom/android/internal/protolog/common/IProtoLogGroup;",
- "Lcom/android/internal/protolog/common/LogDataType;",
- "Lcom/android/internal/protolog/common/ProtoLog;",
- "Lcom/android/internal/protolog/ProtoLogImpl;",
- "Lcom/android/internal/protolog/ProtoLogViewerConfigReader;",
- "Lcom/android/internal/util/FrameworkStatsLog;"
- );
+ ImmutableSet.of(
+ "Landroid/annotation/AnimatorRes;",
+ "Landroid/annotation/AnimRes;",
+ "Landroid/annotation/AnyRes;",
+ "Landroid/annotation/AnyThread;",
+ "Landroid/annotation/AppIdInt;",
+ "Landroid/annotation/ArrayRes;",
+ "Landroid/annotation/AttrRes;",
+ "Landroid/annotation/BinderThread;",
+ "Landroid/annotation/BoolRes;",
+ "Landroid/annotation/BroadcastBehavior;",
+ "Landroid/annotation/BytesLong;",
+ "Landroid/annotation/CallbackExecutor;",
+ "Landroid/annotation/CallSuper;",
+ "Landroid/annotation/CheckResult;",
+ "Landroid/annotation/ColorInt;",
+ "Landroid/annotation/ColorLong;",
+ "Landroid/annotation/ColorRes;",
+ "Landroid/annotation/Condemned;",
+ "Landroid/annotation/CurrentTimeMillisLong;",
+ "Landroid/annotation/CurrentTimeSecondsLong;",
+ "Landroid/annotation/DimenRes;",
+ "Landroid/annotation/Dimension;",
+ "Landroid/annotation/DrawableRes;",
+ "Landroid/annotation/DurationMillisLong;",
+ "Landroid/annotation/ElapsedRealtimeLong;",
+ "Landroid/annotation/FloatRange;",
+ "Landroid/annotation/FontRes;",
+ "Landroid/annotation/FractionRes;",
+ "Landroid/annotation/HalfFloat;",
+ "Landroid/annotation/Hide;",
+ "Landroid/annotation/IdRes;",
+ "Landroid/annotation/IntDef;",
+ "Landroid/annotation/IntegerRes;",
+ "Landroid/annotation/InterpolatorRes;",
+ "Landroid/annotation/IntRange;",
+ "Landroid/annotation/LayoutRes;",
+ "Landroid/annotation/LongDef;",
+ "Landroid/annotation/MainThread;",
+ "Landroid/annotation/MenuRes;",
+ "Landroid/annotation/NavigationRes;",
+ "Landroid/annotation/NonNull;",
+ "Landroid/annotation/Nullable;",
+ "Landroid/annotation/PluralsRes;",
+ "Landroid/annotation/Px;",
+ "Landroid/annotation/RawRes;",
+ "Landroid/annotation/RequiresFeature;",
+ "Landroid/annotation/RequiresPermission;",
+ "Landroid/annotation/SdkConstant;",
+ "Landroid/annotation/Size;",
+ "Landroid/annotation/StringDef;",
+ "Landroid/annotation/StringRes;",
+ "Landroid/annotation/StyleableRes;",
+ "Landroid/annotation/StyleRes;",
+ "Landroid/annotation/SuppressAutoDoc;",
+ "Landroid/annotation/SuppressLint;",
+ "Landroid/annotation/SystemApi;",
+ "Landroid/annotation/SystemService;",
+ "Landroid/annotation/TargetApi;",
+ "Landroid/annotation/TestApi;",
+ "Landroid/annotation/TransitionRes;",
+ "Landroid/annotation/UiThread;",
+ "Landroid/annotation/UserHandleAware;",
+ "Landroid/annotation/UserIdInt;",
+ "Landroid/annotation/Widget;",
+ "Landroid/annotation/WorkerThread;",
+ "Landroid/annotation/XmlRes;",
+ "Landroid/gsi/AvbPublicKey;",
+ "Landroid/gsi/GsiProgress;",
+ "Landroid/gsi/IGsiService;",
+ "Landroid/gsi/IGsiServiceCallback;",
+ "Landroid/gsi/IImageService;",
+ "Landroid/gsi/IProgressCallback;",
+ "Landroid/gsi/MappedImage;",
+ "Landroid/hardware/contexthub/V1_0/AsyncEventType;",
+ "Landroid/hardware/contexthub/V1_0/ContextHub;",
+ "Landroid/hardware/contexthub/V1_0/ContextHubMsg;",
+ "Landroid/hardware/contexthub/V1_0/HostEndPoint;",
+ "Landroid/hardware/contexthub/V1_0/HubAppInfo;",
+ "Landroid/hardware/contexthub/V1_0/HubMemoryFlag;",
+ "Landroid/hardware/contexthub/V1_0/HubMemoryType;",
+ "Landroid/hardware/contexthub/V1_0/IContexthub;",
+ "Landroid/hardware/contexthub/V1_0/IContexthubCallback;",
+ "Landroid/hardware/contexthub/V1_0/MemRange;",
+ "Landroid/hardware/contexthub/V1_0/NanoAppBinary;",
+ "Landroid/hardware/contexthub/V1_0/NanoAppFlags;",
+ "Landroid/hardware/contexthub/V1_0/PhysicalSensor;",
+ "Landroid/hardware/contexthub/V1_0/Result;",
+ "Landroid/hardware/contexthub/V1_0/SensorType;",
+ "Landroid/hardware/contexthub/V1_0/TransactionResult;",
+ "Landroid/hardware/usb/gadget/V1_0/GadgetFunction;",
+ "Landroid/hardware/usb/gadget/V1_0/IUsbGadget;",
+ "Landroid/hardware/usb/gadget/V1_0/IUsbGadgetCallback;",
+ "Landroid/hardware/usb/gadget/V1_0/Status;",
+ "Landroid/os/IDumpstate;",
+ "Landroid/os/IDumpstateListener;",
+ "Landroid/os/IInstalld;",
+ "Landroid/os/IStoraged;",
+ "Landroid/os/IVold;",
+ "Landroid/os/IVoldListener;",
+ "Landroid/os/IVoldMountCallback;",
+ "Landroid/os/IVoldTaskListener;",
+ "Landroid/os/storage/CrateMetadata;",
+ "Landroid/view/LayerMetadataKey;",
+ "Lcom/android/internal/annotations/GuardedBy;",
+ "Lcom/android/internal/annotations/Immutable;",
+ "Lcom/android/internal/annotations/VisibleForNative;",
+ "Lcom/android/internal/annotations/VisibleForTesting;",
+ // TODO(b/173649240): due to an oversight, some new overlaps slipped through
+ // in S.
+ "Landroid/hardware/usb/gadget/V1_1/IUsbGadget;",
+ "Landroid/hardware/usb/gadget/V1_2/GadgetFunction;",
+ "Landroid/hardware/usb/gadget/V1_2/IUsbGadget;",
+ "Landroid/hardware/usb/gadget/V1_2/IUsbGadgetCallback;",
+ "Landroid/hardware/usb/gadget/V1_2/UsbSpeed;",
+ "Landroid/os/BlockUntrustedTouchesMode;",
+ "Landroid/os/CreateAppDataArgs;",
+ "Landroid/os/CreateAppDataResult;",
+ "Landroid/os/IInputConstants;",
+ "Landroid/os/InputEventInjectionResult;",
+ "Landroid/os/InputEventInjectionSync;",
+ "Landroid/os/TouchOcclusionMode;",
+ "Lcom/android/internal/protolog/common/BitmaskConversionException;",
+ "Lcom/android/internal/protolog/common/InvalidFormatStringException;",
+ "Lcom/android/internal/protolog/common/IProtoLogGroup;",
+ "Lcom/android/internal/protolog/common/LogDataType;",
+ "Lcom/android/internal/protolog/common/ProtoLog;",
+ "Lcom/android/internal/protolog/ProtoLogImpl;",
+ "Lcom/android/internal/protolog/ProtoLogViewerConfigReader;",
+ "Lcom/android/internal/util/FrameworkStatsLog;"
+ );
/**
* Ensure that there are no duplicate classes among jars listed in BOOTCLASSPATH.
@@ -217,10 +201,9 @@
@Test
public void testBootclasspath_nonDuplicateClasses() throws Exception {
assumeTrue(ApiLevelUtil.isAfter(getDevice(), 29));
- runWithTempDir(tmpDir -> {
- final Set<DeviceFile> bcpJarFiles = pullJarsFromEnvVariable(tmpDir, "BOOTCLASSPATH");
- checkClassDuplicatesMatchAllowlist(bcpJarFiles, ImmutableSet.of());
- });
+ ImmutableList<String> jars =
+ Classpaths.getJarsOnClasspath(getDevice(), BOOTCLASSPATH);
+ assertThat(getDuplicateClasses(jars)).isEmpty();
}
/**
@@ -229,11 +212,9 @@
@Test
public void testSystemServerClasspath_nonDuplicateClasses() throws Exception {
assumeTrue(ApiLevelUtil.isAfter(getDevice(), 29));
- runWithTempDir(tmpDir -> {
- final Set<DeviceFile> sscpJarFiles =
- pullJarsFromEnvVariable(tmpDir, "SYSTEMSERVERCLASSPATH");
- checkClassDuplicatesMatchAllowlist(sscpJarFiles, ImmutableSet.of());
- });
+ ImmutableList<String> jars =
+ Classpaths.getJarsOnClasspath(getDevice(), SYSTEMSERVERCLASSPATH);
+ assertThat(getDuplicateClasses(jars)).isEmpty();
}
/**
@@ -241,26 +222,32 @@
* SYSTEMSERVERCLASSPATH.
*/
@Test
- public void testBootClassPathAndSystemServerClasspath_nonDuplicateClasses() throws Exception {
+ public void testBootClasspathAndSystemServerClasspath_nonDuplicateClasses() throws Exception {
assumeTrue(ApiLevelUtil.isAfter(getDevice(), 29));
- runWithTempDir(tmpDir -> {
- final Set<DeviceFile> allJarFiles = Sets.union(
- pullJarsFromEnvVariable(tmpDir, "BOOTCLASSPATH"),
- pullJarsFromEnvVariable(tmpDir, "SYSTEMSERVERCLASSPATH")
- );
- checkClassDuplicatesMatchAllowlist(allJarFiles, BCP_AND_SSCP_OVERLAP_BURNDOWN_LIST);
- });
+ ImmutableList.Builder<String> jars = ImmutableList.builder();
+ jars.addAll(Classpaths.getJarsOnClasspath(getDevice(), BOOTCLASSPATH));
+ jars.addAll(Classpaths.getJarsOnClasspath(getDevice(), SYSTEMSERVERCLASSPATH));
+
+ Multimap<String, String> duplicates = getDuplicateClasses(jars.build());
+ Multimap<String, String> filtered = Multimaps.filterKeys(duplicates,
+ duplicate -> !BCP_AND_SSCP_OVERLAP_BURNDOWN_LIST.contains(duplicate));
+
+ assertThat(filtered).isEmpty();
}
/**
* Ensure that there are no duplicate classes among APEX jars listed in BOOTCLASSPATH.
*/
@Test
- public void testBootclasspath_nonDuplicateApexJarClasses() throws Exception {
- runWithTempDir(tmpDir -> {
- final Set<DeviceFile> bcpJarFiles = pullJarsFromEnvVariable(tmpDir, "BOOTCLASSPATH");
- checkClassDuplicatesNotInApexJars(bcpJarFiles);
- });
+ public void testBootClasspath_nonDuplicateApexJarClasses() throws Exception {
+ ImmutableList<String> jars =
+ Classpaths.getJarsOnClasspath(getDevice(), BOOTCLASSPATH);
+
+ Multimap<String, String> duplicates = getDuplicateClasses(jars);
+ Multimap<String, String> filtered =
+ Multimaps.filterValues(duplicates, jar -> jar.startsWith("/apex/"));
+
+ assertThat(filtered).isEmpty();
}
/**
@@ -268,11 +255,14 @@
*/
@Test
public void testSystemServerClasspath_nonDuplicateApexJarClasses() throws Exception {
- runWithTempDir(tmpDir -> {
- final Set<DeviceFile> sscpJarFiles =
- pullJarsFromEnvVariable(tmpDir, "SYSTEMSERVERCLASSPATH");
- checkClassDuplicatesNotInApexJars(sscpJarFiles);
- });
+ ImmutableList<String> jars =
+ Classpaths.getJarsOnClasspath(getDevice(), SYSTEMSERVERCLASSPATH);
+
+ Multimap<String, String> duplicates = getDuplicateClasses(jars);
+ Multimap<String, String> filtered =
+ Multimaps.filterValues(duplicates, jar -> jar.startsWith("/apex/"));
+
+ assertThat(filtered).isEmpty();
}
/**
@@ -280,168 +270,48 @@
* SYSTEMSERVERCLASSPATH.
*/
@Test
- public void testBootClassPathAndSystemServerClasspath_nonApexDuplicateClasses()
+ public void testBootClasspathAndSystemServerClasspath_nonApexDuplicateClasses()
throws Exception {
- runWithTempDir(tmpDir -> {
- final Set<DeviceFile> allJarFiles = Sets.union(
- pullJarsFromEnvVariable(tmpDir, "BOOTCLASSPATH"),
- pullJarsFromEnvVariable(tmpDir, "SYSTEMSERVERCLASSPATH")
- );
- checkClassDuplicatesNotInApexJars(allJarFiles);
- });
- }
+ ImmutableList.Builder<String> jars = ImmutableList.builder();
+ jars.addAll(Classpaths.getJarsOnClasspath(getDevice(), BOOTCLASSPATH));
+ jars.addAll(Classpaths.getJarsOnClasspath(getDevice(), SYSTEMSERVERCLASSPATH));
- private String getEnvVariable(String var) {
- try {
- return getDevice().executeShellCommand("echo $" + var).trim();
- } catch(DeviceNotAvailableException e) {
- throw new RuntimeException(e);
- }
- }
+ Multimap<String, String> duplicates = getDuplicateClasses(jars.build());
+ Multimap<String, String> filtered = Multimaps.filterKeys(duplicates,
+ duplicate -> !BCP_AND_SSCP_OVERLAP_BURNDOWN_LIST.contains(duplicate));
+ filtered = Multimaps.filterValues(filtered, jar -> jar.startsWith("/apex/"));
- private DeviceFile pullFromDevice(String devicePath, File tmpDir) {
- try {
- final File hostFile = Paths.get(tmpDir.getAbsolutePath(), devicePath).toFile();
- // Ensure the destination directory structure exists.
- hostFile.getParentFile().mkdirs();
- final String hostPath = hostFile.getAbsolutePath();
- getDevice().executeAdbCommand(ADB_TIMEOUT_MILLIS, "pull", devicePath, hostPath);
- return new DeviceFile(devicePath, hostPath);
- } catch (Exception e) {
- throw new RuntimeException("Failed to pull " + devicePath, e);
- }
+ assertThat(filtered).isEmpty();
}
/**
* Gets the duplicate classes within a list of jar files.
- * @param jars A list of jar files.
- * @return A multimap with the class name as a key and the jar files as a value.
+ *
+ * @param jars a list of jar files.
+ * @return a multimap with the class name as a key and the jar files as a value.
*/
- private Multimap<String, DeviceFile> getDuplicateClasses(Set<DeviceFile> jars)
- throws Exception {
- final Multimap<String, DeviceFile> allClasses = HashMultimap.create();
- final Multimap<String, DeviceFile> duplicateClasses = HashMultimap.create();
- for (DeviceFile deviceFile : jars) {
- final File jarFile = new File(deviceFile.hostPath);
- final MultiDexContainer<? extends DexBackedDexFile> container =
- DexFileFactory.loadDexContainer(jarFile, Opcodes.getDefault());
- final List<String> entryNames = container.getDexEntryNames();
- for (String entryName : entryNames) {
- final DexFile dexFile = container.getEntry(entryName);
- for (ClassDef classDef : dexFile.getClasses()) {
- allClasses.put(classDef.getType(), deviceFile);
+ private Multimap<String, String> getDuplicateClasses(ImmutableCollection<String> jars)
+ throws Exception {
+ final Multimap<String, String> allClasses = HashMultimap.create();
+ for (String jar : jars) {
+ ImmutableSet<ClassDef> classes = Classpaths.getClassDefsFromJar(getDevice(), jar);
+ for (ClassDef classDef : classes) {
+ // No need to worry about inner classes, as they always go with their parent.
+ if (!classDef.getType().contains("$")) {
+ allClasses.put(classDef.getType(), jar);
}
}
}
- for (Entry<String, Collection<DeviceFile>> entry : allClasses.asMap().entrySet()) {
- if (entry.getValue().size() > 1) {
- CLog.i("Class %s is duplicated in %s", entry.getKey(),
- entry.getValue().stream().map(x -> x.getJarName()).collect(toSet()));
- duplicateClasses.putAll(entry.getKey(), entry.getValue());
+ final Multimap<String, String> duplicates = HashMultimap.create();
+ for (String clazz : allClasses.keySet()) {
+ Collection<String> jarsWithClazz = allClasses.get(clazz);
+ if (jarsWithClazz.size() > 1) {
+ CLog.i("Class %s is duplicated in %s", clazz, jarsWithClazz);
+ duplicates.putAll(clazz, jarsWithClazz);
}
}
- return duplicateClasses;
- }
- /**
- * Checks that the duplicate classes in a set of jars exactly match a given allowlist.
- */
- private void checkClassDuplicatesMatchAllowlist(Set<DeviceFile> jars, Set<String> allowlist)
- throws Exception {
- // Collect classes which appear in at least two distinct jar files.
- Multimap<String, DeviceFile> duplicateClasses = getDuplicateClasses(jars);
- Set<String> deniedClasses = new HashSet<>();
- deniedClasses.addAll(duplicateClasses.keySet());
- deniedClasses.removeAll(allowlist);
- assertThat(deniedClasses).isEmpty();
- }
-
- /**
- * Checks that the duplicate classes are not in APEX jars.
- */
- private void checkClassDuplicatesNotInApexJars(Set<DeviceFile> jars)
- throws Exception {
- final Multimap<String, DeviceFile> jarClasses = getDuplicateClasses(jars);
- for (Entry<String, Collection<DeviceFile>> entry : jarClasses.asMap().entrySet()) {
- final String className = entry.getKey();
- final Collection<DeviceFile> filesWithClass = entry.getValue();
- // Check that jars that define the same class are not part of apexes.
- for (DeviceFile jarFile : filesWithClass) {
- assertWithMessage("%s is available in: %s, of which %s is an APEX jar",
- className, filesWithClass, jarFile.devicePath)
- .that(jarFile.devicePath.startsWith("/apex/"))
- .isFalse();
- }
- }
- }
-
- /**
- * Retrieve jar files from the device, based on an env variable.
- * @param tmpDir The temporary directory where the file will be dumped.
- * @param variable The environment variable containing the colon separated jar files.
- * @return A {@link java.util.Set} with the pulled {@link DeviceFile} instances.
- */
- private Set<DeviceFile> pullJarsFromEnvVariable(File tmpDir, String variable) {
- return Arrays.asList(getEnvVariable(variable).split(":")).stream()
- .map(fileName -> pullFromDevice(fileName, tmpDir))
- .collect(toSet());
- }
-
- private void runWithTempDir(TempDirRunnable runnable) throws Exception {
- final File tmpDir = Files.createTempDirectory("strictjavapackages").toFile();
- try {
- runnable.runWithTempDir(tmpDir);
- } finally {
- tmpDir.delete();
- }
- }
-
- private interface TempDirRunnable {
- public void runWithTempDir(File tempDir) throws Exception;
- }
-
- /**
- * Class representing a device artifact that was pulled for a test method.
- *
- * <p> Contains the local and on-device paths.
- */
- private static final class DeviceFile {
- public final String devicePath;
- public final String hostPath;
- public DeviceFile(String devicePath, String hostPath) {
- this.devicePath = devicePath;
- this.hostPath = hostPath;
- }
-
- public String getJarName() {
- return devicePath.substring(devicePath.lastIndexOf('/') + 1);
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- }
- if (other == null) {
- return false;
- }
- if (!(other instanceof DeviceFile)) {
- return false;
- }
- DeviceFile that = (DeviceFile) other;
- return Objects.equals(this.devicePath, that.devicePath)
- && Objects.equals(this.hostPath, that.hostPath);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(devicePath, hostPath);
- }
-
- @Override
- public String toString() {
- return String.format("DeviceFile(devicePath=%s,hostPath=%s)", devicePath, hostPath);
- }
+ return duplicates;
}
}
diff --git a/hostsidetests/appsecurity/OWNERS b/hostsidetests/appsecurity/OWNERS
index d561b80..e4d9d04 100644
--- a/hostsidetests/appsecurity/OWNERS
+++ b/hostsidetests/appsecurity/OWNERS
@@ -1,32 +1,35 @@
# Bug component: 533114
toddke@google.com
+patb@google.com
per-file AccessSerialNumberTest.java = moltmann@google.com
per-file ApexSignatureVerificationTest.java = dariofreni@google.com
-per-file ApplicationVisibilityTest.java = toddke@google.com
-per-file AppDataIsolationTests.java = rickywai@google.com
+per-file ApplicationVisibilityTest.java = toddke@google.com,patb@google.com
+per-file AppDataIsolationTests.java = rickywai@google.com,alanstokes@google.com
per-file AppOpsTest.java = moltmann@google.com
per-file AppSecurityTests.java = cbrubaker@google.com
-per-file AuthBoundKeyTest.java = cbrubaker@google.com
-per-file BaseInstallMultiple.java = toddke@google.com
+per-file AuthBoundKeyTest.java = file:test-apps/AuthBoundKeyApp/OWNERS
+per-file BaseInstallMultiple.java = toddke@google.com,patb@google.com
per-file CorruptApkTests.java = rtmitchell@google.com
per-file DeviceIdentifierTest.java = cbrubaker@google.com
-per-file EphemeralTest.java = toddke@google.com
-per-file InstantAppUserTest.java = toddke@google.com
-per-file InstantCookieHostTest.java = toddke@google.com
+per-file EphemeralTest.java = toddke@google.com,patb@google.com
+per-file ExternalStorageHostTest.java = nandana@google.com
+per-file ExternalStorageHostTest.java = zezeozue@google.com
+per-file InstantAppUserTest.java = toddke@google.com,patb@google.com
+per-file InstantCookieHostTest.java = toddke@google.com,patb@google.com
per-file IsolatedSplitsTests.java = patb@google.com,toddke@google.com
per-file KeySetHostTest.java = cbrubaker@google.com
per-file ListeningPortsTest.java = cbrubaker@google.com
-per-file MajorVersionTest.java = toddke@google.com
+per-file MajorVersionTest.java = toddke@google.com,patb@google.com
per-file OverlayHostTest.java = rtmitchell@google.com
per-file Package* = chiuwinson@google.com,patb@google.com,toddke@google.com
per-file PermissionsHostTest.java = moltmann@google.com
per-file Pkg* = chiuwinson@google.com,patb@google.com,toddke@google.com
per-file PkgInstallSignatureVerificationTest.java = cbrubaker@google.com
-per-file PrivilegedUpdateTests.java = toddke@google.com
+per-file PrivilegedUpdateTests.java = toddke@google.com,patb@google.com
per-file ReviewPermissionHelper = moltmann@google.com
per-file RequestsOnlyCalendarApp22.java = moltmann@google.com
-per-file SharedUserIdTest.java = toddke@google.com
-per-file SplitTests.java = patb@google.com,toddke@google.com
+per-file SharedUserIdTest.java = toddke@google.com,patb@google.com
+per-file SplitTests.java = patb@google.com,toddke@google.com,patb@google.com
per-file UseEmbeddedDexTest.java = victorhsieh@google.com
# test apps
per-file BasePermissionsTest.java = moltmann@google.com
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ResumeOnRebootHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ResumeOnRebootHostTest.java
index 3023cd9..cbe07f0 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ResumeOnRebootHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ResumeOnRebootHostTest.java
@@ -66,6 +66,7 @@
private static final long SHUTDOWN_TIME_MS = TimeUnit.SECONDS.toMicros(30);
private static final int USER_SYSTEM = 0;
+ private static final int USER_SWITCH_TIMEOUT_SECONDS = 10;
private static final long USER_SWITCH_WAIT = TimeUnit.SECONDS.toMillis(10);
private boolean mSupportsMultiUser;
@@ -98,6 +99,9 @@
int[] users = Utils.prepareSingleUser(getDevice());
int initialUser = users[0];
+ // Clean up the server based parameters for HAL based test.
+ deviceCleanupServerBasedParameter();
+
try {
installTestPackages();
@@ -140,6 +144,8 @@
int managedUserId = createManagedProfile(initialUser);
+ deviceCleanupServerBasedParameter();
+
try {
// Set up test app and secure lock screens
installTestPackages();
@@ -186,6 +192,8 @@
int initialUser = users[0];
int secondaryUser = users[1];
+ deviceCleanupServerBasedParameter();
+
try {
// Set up test app and secure lock screens
installTestPackages();
@@ -244,6 +252,8 @@
int initialUser = users[0];
int secondaryUser = users[1];
+ deviceCleanupServerBasedParameter();
+
try {
installTestPackages();
@@ -419,12 +429,24 @@
private void deviceSetupServerBasedParameter() throws Exception {
getDevice().executeShellCommand("device_config put ota server_based_ror_enabled true");
+ String res = getDevice().executeShellCommand(
+ "device_config get ota server_based_ror_enabled");
+ if (res == null || !res.contains("true")) {
+ fail("could not set up server based ror");
+ }
+
getDevice().executeShellCommand(
"cmd lock_settings set-resume-on-reboot-provider-package " + PKG);
}
private void deviceCleanupServerBasedParameter() throws Exception {
getDevice().executeShellCommand("device_config put ota server_based_ror_enabled false");
+ String res = getDevice().executeShellCommand(
+ "device_config get ota server_based_ror_enabled");
+ if (res == null || !res.contains("false")) {
+ fail("could not clean up server based ror");
+ }
+
getDevice().executeShellCommand(
"cmd lock_settings set-resume-on-reboot-provider-package ");
}
@@ -526,7 +548,7 @@
*/
private void switchUser(int userId) throws Exception {
getDevice().switchUser(userId);
- HostSideTestUtils.waitUntil("Could not switch users", 5,
+ HostSideTestUtils.waitUntil("Could not switch users", USER_SWITCH_TIMEOUT_SECONDS,
() -> getDevice().getCurrentUser() == userId);
Thread.sleep(USER_SWITCH_WAIT);
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/UseEmbeddedDexTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/UseEmbeddedDexTest.java
index 9db3ac2..0d34c46 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/UseEmbeddedDexTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/UseEmbeddedDexTest.java
@@ -47,6 +47,13 @@
}
@Test
+ public void testIsolatedService() throws Exception {
+ new InstallMultiple().addFile(APK_CANONICAL).run();
+ getDevice().executeShellCommand("cmd package compile -f -m speed " + PACKAGE_NAME);
+ runDeviceTests(PACKAGE_NAME, PACKAGE_NAME + ".EmbeddedDexTest", "testIsolatedService");
+ }
+
+ @Test
public void testBadInstallWithCompressedDex() throws Exception {
new InstallMultiple().addFile(APK_DEX_COMPRESSED).runExpectingFailure();
}
diff --git a/hostsidetests/appsecurity/test-apps/AuthBoundKeyApp/OWNERS b/hostsidetests/appsecurity/test-apps/AuthBoundKeyApp/OWNERS
new file mode 100644
index 0000000..4e06da3
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/AuthBoundKeyApp/OWNERS
@@ -0,0 +1,8 @@
+# Bug component: 533114
+hasinitg@google.com
+jbires@google.com
+jdanis@google.com
+swillden@google.com
+toddke@google.com
+patb@google.com
+zeuthen@google.com
diff --git a/hostsidetests/appsecurity/test-apps/AuthBoundKeyApp/src/com/android/cts/authboundkey/AuthBoundKeyAppTest.java b/hostsidetests/appsecurity/test-apps/AuthBoundKeyApp/src/com/android/cts/authboundkey/AuthBoundKeyAppTest.java
index 1f2adfd..d3960d3 100644
--- a/hostsidetests/appsecurity/test-apps/AuthBoundKeyApp/src/com/android/cts/authboundkey/AuthBoundKeyAppTest.java
+++ b/hostsidetests/appsecurity/test-apps/AuthBoundKeyApp/src/com/android/cts/authboundkey/AuthBoundKeyAppTest.java
@@ -74,11 +74,16 @@
keyStore.load(null);
try {
SecretKey secretKey = (SecretKey) keyStore.getKey(KEY_NAME, null);
+ // This test verifies that the given key is no longer usable after removing the LSKF.
+ // In Keystore 2.0 we don't keep invalidated keys around. So we cannot diagnose that
+ // a key was invalidated. It simply does not exist. Thus we expect null.
+ // An UnrecoverableKeyException is also acceptable (see below) and was the typical
+ // behavior for Keystore 1.0.
+ if (secretKey == null) return;
} catch (UnrecoverableKeyException e) {
- // This is correct behavior
return;
}
- fail("Expected an UnrecoverableKeyException");
+ fail("Expected an UnrecoverableKeyException or null");
}
}
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/OWNERS b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/OWNERS
index 87e75ec..bdc654a 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/OWNERS
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/OWNERS
@@ -1,2 +1,3 @@
# Bug component: 533114
toddke@google.com
+patb@google.com
diff --git a/hostsidetests/appsecurity/test-apps/InstantCookieApp/OWNERS b/hostsidetests/appsecurity/test-apps/InstantCookieApp/OWNERS
index 87e75ec..bdc654a 100644
--- a/hostsidetests/appsecurity/test-apps/InstantCookieApp/OWNERS
+++ b/hostsidetests/appsecurity/test-apps/InstantCookieApp/OWNERS
@@ -1,2 +1,3 @@
# Bug component: 533114
toddke@google.com
+patb@google.com
diff --git a/hostsidetests/appsecurity/test-apps/InstantCookieApp2/OWNERS b/hostsidetests/appsecurity/test-apps/InstantCookieApp2/OWNERS
index 87e75ec..bdc654a 100644
--- a/hostsidetests/appsecurity/test-apps/InstantCookieApp2/OWNERS
+++ b/hostsidetests/appsecurity/test-apps/InstantCookieApp2/OWNERS
@@ -1,2 +1,3 @@
# Bug component: 533114
toddke@google.com
+patb@google.com
diff --git a/hostsidetests/appsecurity/test-apps/InstantUpgradeApp/OWNERS b/hostsidetests/appsecurity/test-apps/InstantUpgradeApp/OWNERS
index 87e75ec..bdc654a 100644
--- a/hostsidetests/appsecurity/test-apps/InstantUpgradeApp/OWNERS
+++ b/hostsidetests/appsecurity/test-apps/InstantUpgradeApp/OWNERS
@@ -1,2 +1,3 @@
# Bug component: 533114
toddke@google.com
+patb@google.com
diff --git a/hostsidetests/appsecurity/test-apps/KeyRotationTest/Android.mk b/hostsidetests/appsecurity/test-apps/KeyRotationTest/Android.mk
index 43acdfe..c453d7a 100644
--- a/hostsidetests/appsecurity/test-apps/KeyRotationTest/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/KeyRotationTest/Android.mk
@@ -36,6 +36,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := cts_signature_query_service
LOCAL_COMPATIBILITY_SUITE := cts general-tests
LOCAL_CERTIFICATE := $(cert_dir)/ec-p256
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
include $(BUILD_CTS_SUPPORT_PACKAGE)
# This is the second version of the test app signed with the rotated signing
@@ -50,6 +52,8 @@
LOCAL_CERTIFICATE := $(cert_dir)/ec-p256_2
LOCAL_ADDITIONAL_CERTIFICATES := $(cert_dir)/ec-p256
LOCAL_CERTIFICATE_LINEAGE := $(cert_dir)/ec-p256-por_1_2-default-caps
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
include $(BUILD_CTS_SUPPORT_PACKAGE)
# This is the third version of the test app signed with the same rotated
@@ -64,6 +68,8 @@
LOCAL_CERTIFICATE := $(cert_dir)/ec-p256_2
LOCAL_ADDITIONAL_CERTIFICATES := $(cert_dir)/ec-p256
LOCAL_CERTIFICATE_LINEAGE := $(cert_dir)/ec-p256-por_1_2-default-caps
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
include $(BUILD_CTS_SUPPORT_PACKAGE)
cert_dir :=
diff --git a/hostsidetests/appsecurity/test-apps/KeyRotationTest/ServiceTest/Android.mk b/hostsidetests/appsecurity/test-apps/KeyRotationTest/ServiceTest/Android.mk
index 016687c..0faf3cd 100644
--- a/hostsidetests/appsecurity/test-apps/KeyRotationTest/ServiceTest/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/KeyRotationTest/ServiceTest/Android.mk
@@ -24,6 +24,8 @@
# the PackageManager checkSignatures APIs.
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsSignatureQueryServiceTest
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := cts_signature_query_service androidx.test.core androidx.test.rules
@@ -36,6 +38,8 @@
# lineage as v2 and v3 of the CtsSignatureQueryService test app.
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsSignatureQueryServiceTest_v2
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := cts_signature_query_service androidx.test.core androidx.test.rules
@@ -47,4 +51,3 @@
include $(BUILD_CTS_SUPPORT_PACKAGE)
cert_dir :=
-
diff --git a/hostsidetests/appsecurity/test-apps/MajorVersionApp/OWNERS b/hostsidetests/appsecurity/test-apps/MajorVersionApp/OWNERS
index 87e75ec..bdc654a 100644
--- a/hostsidetests/appsecurity/test-apps/MajorVersionApp/OWNERS
+++ b/hostsidetests/appsecurity/test-apps/MajorVersionApp/OWNERS
@@ -1,2 +1,3 @@
# Bug component: 533114
toddke@google.com
+patb@google.com
diff --git a/hostsidetests/appsecurity/test-apps/NoRestartApp/OWNERS b/hostsidetests/appsecurity/test-apps/NoRestartApp/OWNERS
index 87e75ec..bdc654a 100644
--- a/hostsidetests/appsecurity/test-apps/NoRestartApp/OWNERS
+++ b/hostsidetests/appsecurity/test-apps/NoRestartApp/OWNERS
@@ -1,2 +1,3 @@
# Bug component: 533114
toddke@google.com
+patb@google.com
diff --git a/hostsidetests/appsecurity/test-apps/OrderedActivityApp/OWNERS b/hostsidetests/appsecurity/test-apps/OrderedActivityApp/OWNERS
index 87e75ec..bdc654a 100644
--- a/hostsidetests/appsecurity/test-apps/OrderedActivityApp/OWNERS
+++ b/hostsidetests/appsecurity/test-apps/OrderedActivityApp/OWNERS
@@ -1,2 +1,3 @@
# Bug component: 533114
toddke@google.com
+patb@google.com
diff --git a/hostsidetests/appsecurity/test-apps/PackageAccessApp/OWNERS b/hostsidetests/appsecurity/test-apps/PackageAccessApp/OWNERS
index 87e75ec..bdc654a 100644
--- a/hostsidetests/appsecurity/test-apps/PackageAccessApp/OWNERS
+++ b/hostsidetests/appsecurity/test-apps/PackageAccessApp/OWNERS
@@ -1,2 +1,3 @@
# Bug component: 533114
toddke@google.com
+patb@google.com
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/OWNERS b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/OWNERS
index 87e75ec..bdc654a 100644
--- a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/OWNERS
+++ b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/OWNERS
@@ -1,2 +1,3 @@
# Bug component: 533114
toddke@google.com
+patb@google.com
diff --git a/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgrade.apk b/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm/CtsShimPrivUpgrade.apk
index b6f7cd0..53d1527 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 112b9db..54a5daa 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 9f1d735..0c37618 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 a8819be..f8e305b 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/SharedUidInstall/OWNERS b/hostsidetests/appsecurity/test-apps/SharedUidInstall/OWNERS
index 87e75ec..bdc654a 100644
--- a/hostsidetests/appsecurity/test-apps/SharedUidInstall/OWNERS
+++ b/hostsidetests/appsecurity/test-apps/SharedUidInstall/OWNERS
@@ -1,2 +1,3 @@
# Bug component: 533114
toddke@google.com
+patb@google.com
diff --git a/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/OWNERS b/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/OWNERS
index 87e75ec..bdc654a 100644
--- a/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/OWNERS
+++ b/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/OWNERS
@@ -1,2 +1,3 @@
# Bug component: 533114
toddke@google.com
+patb@google.com
diff --git a/hostsidetests/appsecurity/test-apps/SimpleAppInstall/OWNERS b/hostsidetests/appsecurity/test-apps/SimpleAppInstall/OWNERS
index 87e75ec..bdc654a 100644
--- a/hostsidetests/appsecurity/test-apps/SimpleAppInstall/OWNERS
+++ b/hostsidetests/appsecurity/test-apps/SimpleAppInstall/OWNERS
@@ -1,2 +1,3 @@
# Bug component: 533114
toddke@google.com
+patb@google.com
diff --git a/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/OWNERS b/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/OWNERS
index 87e75ec..bdc654a 100644
--- a/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/OWNERS
+++ b/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/OWNERS
@@ -1,2 +1,3 @@
# Bug component: 533114
toddke@google.com
+patb@google.com
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
index 08a94b5..404ff07 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
@@ -26,6 +26,8 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsSplitApp
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_SDK_VERSION := current
LOCAL_MIN_SDK_VERSION := 4
LOCAL_PACKAGE_SPLITS := mdpi-v4 hdpi-v4 xhdpi-v4 xxhdpi-v4 v7 fr de
@@ -61,6 +63,8 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsSplitAppDiffRevision
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_PACKAGE_SPLITS := v7
# Tag this module as a cts test artifact
@@ -91,6 +95,8 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsSplitAppDiffVersion
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_PACKAGE_SPLITS := v7
# Tag this module as a cts test artifact
@@ -120,6 +126,8 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsSplitAppDiffCert
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_PACKAGE_SPLITS := v7
# Tag this module as a cts test artifact
@@ -146,6 +154,8 @@
LOCAL_MANIFEST_FILE := needsplit/AndroidManifest.xml
LOCAL_PACKAGE_NAME := CtsNeedSplitApp
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_SDK_VERSION := current
LOCAL_MIN_SDK_VERSION := 4
LOCAL_PACKAGE_SPLITS := xxhdpi-v4
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/NativeTemplate.mk b/hostsidetests/appsecurity/test-apps/SplitApp/NativeTemplate.mk
index b61c5d6..f9ab818 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/NativeTemplate.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/NativeTemplate.mk
@@ -19,6 +19,8 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsSplitApp_ARCHARCH
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_JAVA_RESOURCE_DIRS := raw
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
index 22d0a1a..42a2160 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
@@ -19,6 +19,8 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := CtsSplitAppFeature
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_SDK_VERSION := current
LOCAL_MIN_SDK_VERSION := 4
LOCAL_PACKAGE_SPLITS := v7
@@ -53,6 +55,8 @@
LOCAL_MANIFEST_FILE := needsplit/AndroidManifest.xml
LOCAL_PACKAGE_NAME := CtsNeedSplitFeature
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_SDK_VERSION := current
LOCAL_MIN_SDK_VERSION := 4
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk
index 8eede6c..6d716aa 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk
@@ -19,6 +19,8 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsSplitApp_arm64-v8a
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_SDK_VERSION := current
LOCAL_JAVA_RESOURCE_DIRS := raw
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk
index 234a7d8..9e27161 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk
@@ -19,6 +19,8 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsSplitApp_armeabi-v7a
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_SDK_VERSION := current
LOCAL_JAVA_RESOURCE_DIRS := raw
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk
index 0322dcd..8da02fd 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk
@@ -19,6 +19,8 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsSplitApp_armeabi
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_SDK_VERSION := current
LOCAL_JAVA_RESOURCE_DIRS := raw
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk
index 4ee13ba..533525b 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk
@@ -19,6 +19,8 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsSplitApp_mips
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_SDK_VERSION := current
LOCAL_JAVA_RESOURCE_DIRS := raw
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk
index 03c4305..64ec09a 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk
@@ -19,6 +19,8 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsSplitApp_mips64
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_SDK_VERSION := current
LOCAL_JAVA_RESOURCE_DIRS := raw
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk
index 14144a6..e6a6cf0b 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk
@@ -19,6 +19,8 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsSplitApp_x86
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_SDK_VERSION := current
LOCAL_JAVA_RESOURCE_DIRS := raw
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk
index 462c1cc..456ef11 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk
@@ -19,6 +19,8 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsSplitApp_x86_64
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_SDK_VERSION := current
LOCAL_JAVA_RESOURCE_DIRS := raw
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 f507d40..0d6bcc1 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
@@ -101,26 +101,80 @@
final UiDevice device = UiDevice.getInstance(getInstrumentation());
device.waitForIdle();
- if (!isTV(getContext())) {
- UiScrollable uiScrollable = new UiScrollable(new UiSelector().scrollable(true));
- try {
- uiScrollable.scrollTextIntoView("internal storage");
- } catch (UiObjectNotFoundException e) {
- // Scrolling can fail if the UI is not scrollable
- }
- device.findObject(new UiSelector().textContains("internal storage")).click();
- device.waitForIdle();
+ if (isWatch()) {
+ clearSpaceWatch(device);
+ } else if (isTV()) {
+ clearSpaceTv(device);
+ } else if (isCar()) {
+ clearSpaceCar(device);
+ } else {
+ clearSpaceGeneric(device);
}
- String clearString = isCar(getContext()) ? "Clear storage" : "Clear";
- device.findObject(new UiSelector().textContains(clearString)).click();
- device.waitForIdle();
- device.findObject(new UiSelector().text("OK")).click();
device.waitForIdle();
// Now, disk better be less-full!
assertTrue(getContext().getDataDir().getUsableSpace() > 256_000_000);
}
+ private void clearSpaceGeneric(UiDevice device) throws UiObjectNotFoundException {
+ UiScrollable uiScrollable = new UiScrollable(new UiSelector().scrollable(true));
+ try {
+ uiScrollable.scrollTextIntoView("internal storage");
+ } catch (UiObjectNotFoundException e) {
+ // Scrolling can fail if the UI is not scrollable
+ }
+ device.findObject(new UiSelector().textContains("internal storage")).click();
+ device.waitForIdle();
+
+ device.findObject(new UiSelector().textContains("Clear")).click();
+ device.waitForIdle();
+
+ device.findObject(new UiSelector().text("OK")).click();
+ }
+
+ private void clearSpaceWatch(UiDevice device) throws UiObjectNotFoundException {
+ UiScrollable uiScrollable = new UiScrollable(new UiSelector().scrollable(true));
+ uiScrollable.scrollTextIntoView("App info");
+
+ device.findObject(new UiSelector().textContains("App info")).click();
+ device.waitForIdle();
+
+ uiScrollable.scrollTextIntoView("Clear data");
+ device.waitForIdle();
+
+ device.findObject(new UiSelector().textContains("Clear data")).click();
+ device.waitForIdle();
+
+ UiSelector yesButton = new UiSelector().description("Yes");
+ uiScrollable.scrollIntoView(yesButton);
+ device.waitForIdle();
+
+ device.findObject(yesButton).click();
+ }
+
+ private void clearSpaceTv(UiDevice device) throws UiObjectNotFoundException {
+ device.findObject(new UiSelector().textContains("Clear")).click();
+ device.waitForIdle();
+ device.findObject(new UiSelector().text("OK")).click();
+ }
+
+ private void clearSpaceCar(UiDevice device) throws UiObjectNotFoundException {
+ UiScrollable uiScrollable = new UiScrollable(new UiSelector().scrollable(true));
+ String storageString = "internal storage";
+ try {
+ uiScrollable.scrollTextIntoView(storageString);
+ } catch (UiObjectNotFoundException e) {
+ // Scrolling can fail if the UI is not scrollable
+ }
+ device.findObject(new UiSelector().textContains(storageString)).click();
+ device.waitForIdle();
+
+ device.findObject(new UiSelector().textContains("Clear storage")).click();
+ device.waitForIdle();
+
+ device.findObject(new UiSelector().text("OK")).click();
+ }
+
/**
* Measure ourselves manually.
*/
@@ -326,13 +380,19 @@
assertFalse(new File("/sdcard/cts_top").exists());
}
- private static boolean isTV(Context context) {
- final PackageManager packageManager = context.getPackageManager();
- return packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ private boolean isTV() {
+ return hasFeature(PackageManager.FEATURE_LEANBACK);
}
- private static boolean isCar(Context context) {
- PackageManager pm = context.getPackageManager();
- return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+ private boolean isCar() {
+ return hasFeature(PackageManager.FEATURE_AUTOMOTIVE);
+ }
+
+ private boolean isWatch() {
+ return hasFeature(PackageManager.FEATURE_WATCH);
+ }
+
+ private boolean hasFeature(String feature) {
+ return getContext().getPackageManager().hasSystemFeature(feature);
}
}
\ No newline at end of file
diff --git a/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/Android.bp b/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/Android.bp
index 22bf8d4..a76d28e 100644
--- a/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/Android.bp
@@ -18,48 +18,51 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-android_test_helper_app {
- name: "CtsUseEmbeddedDexApp_Canonical",
+java_defaults {
+ name: "cts_use_embedded_dex_test_defaults",
defaults: ["cts_support_defaults"],
- use_embedded_dex: true,
srcs: ["src/**/*.java"],
sdk_version: "current",
- min_sdk_version: "27",
test_suites: [
"cts",
"general-tests",
],
+ static_libs: [
+ "androidx.test.rules",
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ "ub-uiautomator",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+}
+
+android_test_helper_app {
+ name: "CtsUseEmbeddedDexApp_Canonical",
+ defaults: ["cts_use_embedded_dex_test_defaults"],
+ min_sdk_version: "27",
+ use_embedded_dex: true,
}
android_test_helper_app {
name: "CtsUseEmbeddedDexApp_DexCompressed",
- defaults: ["cts_support_defaults"],
+ defaults: ["cts_use_embedded_dex_test_defaults"],
// Not specifying use_embedded_dex keeps dex compressed
- srcs: ["src/**/*.java"],
- sdk_version: "current",
min_sdk_version: "28",
- test_suites: [
- "cts",
- "general-tests",
- ],
}
android_test_helper_app {
name: "CtsUseEmbeddedDexApp_NotPreferred",
- defaults: ["cts_support_defaults"],
+ defaults: ["cts_use_embedded_dex_test_defaults"],
manifest: "AndroidManifest_use_extracted_dex.xml",
- srcs: ["src/**/*.java"],
- sdk_version: "current",
min_sdk_version: "28",
- test_suites: [
- "cts",
- "general-tests",
- ],
}
android_test_helper_app {
name: "CtsUseEmbeddedDexAppSplit_Canonical",
- defaults: ["cts_support_defaults"],
+ defaults: ["cts_use_embedded_dex_test_defaults"],
manifest: "feature_split/AndroidManifest.xml",
// We want the dex to be uncompressed, but there is a side effect of extra
// android:useEmbeddedDex in the manifest (which the framework will ignore
@@ -68,23 +71,14 @@
srcs: ["feature_split/src/**/*.java"],
sdk_version: "current",
min_sdk_version: "27",
- test_suites: [
- "cts",
- "general-tests",
- ],
}
android_test_helper_app {
name: "CtsUseEmbeddedDexAppSplit_CompressedDex",
- defaults: ["cts_support_defaults"],
+ defaults: ["cts_use_embedded_dex_test_defaults"],
manifest: "feature_split/AndroidManifest.xml",
srcs: ["feature_split/src/**/*.java"],
- sdk_version: "current",
min_sdk_version: "27",
- test_suites: [
- "cts",
- "general-tests",
- ],
}
//android_test_helper_app {
diff --git a/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/AndroidManifest.xml
index 9797cea..dfb6d2a 100644
--- a/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/AndroidManifest.xml
@@ -21,6 +21,16 @@
<application android:useEmbeddedDex="true">
<activity android:name=".EmptyActivity"/>
+
+ <service
+ android:name=".IsolatedService"
+ android:isolatedProcess="true"
+ android:useAppZygote="true" />
+ <uses-library android:name="android.test.runner" />
</application>
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.cts.useembeddeddex" />
+
</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/src/com/android/cts/useembeddeddex/EmbeddedDexTest.java b/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/src/com/android/cts/useembeddeddex/EmbeddedDexTest.java
new file mode 100644
index 0000000..898e6ae
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/src/com/android/cts/useembeddeddex/EmbeddedDexTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.useembeddeddex;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.test.InstrumentationTestCase;
+import android.util.Log;
+import com.android.compatibility.common.util.PollingCheck;
+
+public class EmbeddedDexTest extends InstrumentationTestCase {
+ static final String TAG = "EmbeddedDexTest";
+
+ boolean mServiceConnected = false;
+
+ public void testIsolatedService() throws Exception {
+ // Start and wait for the isolated service.
+ Context context = getInstrumentation().getTargetContext();
+ Intent intent = new Intent(context, IsolatedService.class);
+ ServiceConnection conn = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Log.i(TAG, "Isolated service connected " + name + " " + service);
+ EmbeddedDexTest.this.mServiceConnected = true;
+ }
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Log.i(TAG, "Isolated service disconnected " + name);
+ EmbeddedDexTest.this.mServiceConnected = false;
+ }
+ };
+ try {
+ assertTrue(context.bindService(intent, conn, Context.BIND_AUTO_CREATE));
+ PollingCheck.waitFor(() -> EmbeddedDexTest.this.mServiceConnected);
+ } finally {
+ context.unbindService(conn);
+ }
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/src/com/android/cts/useembeddeddex/EmptyActivity.java b/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/src/com/android/cts/useembeddeddex/EmptyActivity.java
index c25f89a..b33f343 100644
--- a/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/src/com/android/cts/useembeddeddex/EmptyActivity.java
+++ b/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/src/com/android/cts/useembeddeddex/EmptyActivity.java
@@ -18,5 +18,4 @@
import android.app.Activity;
-/** Empty class just to generate some dex */
public class EmptyActivity extends Activity {}
diff --git a/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/src/com/android/cts/useembeddeddex/IsolatedService.java b/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/src/com/android/cts/useembeddeddex/IsolatedService.java
new file mode 100644
index 0000000..6e4b969
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/UseEmbeddedDexApp/src/com/android/cts/useembeddeddex/IsolatedService.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.useembeddeddex;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.util.Log;
+
+public class IsolatedService extends Service {
+ Binder mBinder = new Binder();
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Log.i("IsolatedService", "Service created in pid " + android.os.Process.myPid());
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ Log.i("IsolatedService", "Service bound with pid " + android.os.Process.myPid());
+ return mBinder;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ Log.i("IsolatedService", "Service destroyed in pid " + android.os.Process.myPid());
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/tinyapp/Android.mk b/hostsidetests/appsecurity/test-apps/tinyapp/Android.mk
index 400eeeb..92aca5b 100644
--- a/hostsidetests/appsecurity/test-apps/tinyapp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/tinyapp/Android.mk
@@ -21,12 +21,16 @@
# This is the default test package signed with the default key.
include $(LOCAL_PATH)/base.mk
LOCAL_PACKAGE_NAME := CtsPkgInstallTinyApp
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
include $(BUILD_CTS_SUPPORT_PACKAGE)
# This is the test package v2 signed with the default key.
include $(LOCAL_PATH)/base.mk
LOCAL_MANIFEST_FILE := AndroidManifest-v2.xml
LOCAL_PACKAGE_NAME := CtsPkgInstallTinyAppV2
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
include $(BUILD_CTS_SUPPORT_PACKAGE)
# This is the test package signed using the V1/V2 signature schemes with
@@ -41,6 +45,8 @@
LOCAL_SDK_VERSION := 30
LOCAL_MANIFEST_FILE := AndroidManifest-sandbox-v1.xml
LOCAL_PACKAGE_NAME := v1v2-ec-p256-two-signers-targetSdk-30
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_CERTIFICATE := $(cert_dir)/ec-p256
LOCAL_ADDITIONAL_CERTIFICATES := $(cert_dir)/ec-p256_2
include $(BUILD_CTS_SUPPORT_PACKAGE)
@@ -49,6 +55,8 @@
# with the previous key in the lineage and part of a sharedUid.
include $(LOCAL_PATH)/base.mk
LOCAL_PACKAGE_NAME := v3-ec-p256-1-sharedUid
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_MANIFEST_FILE := AndroidManifest-shareduid.xml
LOCAL_CERTIFICATE := $(cert_dir)/ec-p256
include $(BUILD_CTS_SUPPORT_PACKAGE)
@@ -57,6 +65,8 @@
# a rotated key and one signer in the lineage with default capabilities.
include $(LOCAL_PATH)/base.mk
LOCAL_PACKAGE_NAME := v3-ec-p256-with-por_1_2-default-caps
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_CERTIFICATE := $(cert_dir)/ec-p256_2
LOCAL_ADDITIONAL_CERTIFICATES := $(cert_dir)/ec-p256
LOCAL_CERTIFICATE_LINEAGE := $(cert_dir)/ec-p256-por_1_2-default-caps
@@ -67,6 +77,8 @@
# grant access to the previous key in the lineage to join the sharedUid.
include $(LOCAL_PATH)/base.mk
LOCAL_PACKAGE_NAME := v3-ec-p256-with-por_1_2-default-caps-sharedUid
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_MANIFEST_FILE := AndroidManifest-shareduid.xml
LOCAL_CERTIFICATE := $(cert_dir)/ec-p256_2
LOCAL_ADDITIONAL_CERTIFICATES := $(cert_dir)/ec-p256
@@ -80,6 +92,8 @@
# ancestors are not allowed to be installed in the same sharedUserId.
include $(LOCAL_PATH)/base.mk
LOCAL_PACKAGE_NAME := v3-por_Y_1_2-default-caps-sharedUid
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_MANIFEST_FILE := AndroidManifest-shareduid.xml
LOCAL_CERTIFICATE := $(cert_dir)/ec-p256_2
LOCAL_ADDITIONAL_CERTIFICATES := $(cert_dir)/rsa-2048 $(cert_dir)/ec-p256
@@ -91,6 +105,8 @@
# prevent the previous key in the lineage from joining the sharedUid.
include $(LOCAL_PATH)/base.mk
LOCAL_PACKAGE_NAME := v3-ec-p256-with-por_1_2-no-shUid-cap-sharedUid
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_MANIFEST_FILE := AndroidManifest-shareduid.xml
LOCAL_CERTIFICATE := $(cert_dir)/ec-p256_2
LOCAL_ADDITIONAL_CERTIFICATES := $(cert_dir)/ec-p256
@@ -102,6 +118,8 @@
# grant access to the previous key in the lineage to join the sharedUid.
include $(LOCAL_PATH)/base.mk
LOCAL_PACKAGE_NAME := v3-ec-p256-with-por_1_2-default-caps-sharedUid-companion
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_MANIFEST_FILE := AndroidManifest-companion-shareduid.xml
LOCAL_CERTIFICATE := $(cert_dir)/ec-p256_2
LOCAL_ADDITIONAL_CERTIFICATES := $(cert_dir)/ec-p256
@@ -115,6 +133,8 @@
# ancestors are not allowed to be installed in the same sharedUserId.
include $(LOCAL_PATH)/base.mk
LOCAL_PACKAGE_NAME := v3-por_Z_1_2-default-caps-sharedUid-companion
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_MANIFEST_FILE := AndroidManifest-shareduid.xml
LOCAL_CERTIFICATE := $(cert_dir)/ec-p256_2
LOCAL_ADDITIONAL_CERTIFICATES := $(cert_dir)/dsa-2048 $(cert_dir)/ec-p256
@@ -127,6 +147,8 @@
# with the latest key in the lineage.
include $(LOCAL_PATH)/base.mk
LOCAL_PACKAGE_NAME := v3-ec-p256-2-sharedUid-companion
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_MANIFEST_FILE := AndroidManifest-companion-shareduid.xml
LOCAL_CERTIFICATE := $(cert_dir)/ec-p256_2
include $(BUILD_CTS_SUPPORT_PACKAGE)
@@ -135,9 +157,10 @@
# with the previous key in the lineage and part of a sharedUid.
include $(LOCAL_PATH)/base.mk
LOCAL_PACKAGE_NAME := v3-ec-p256-1-sharedUid-companion2
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_MANIFEST_FILE := AndroidManifest-companion2-shareduid.xml
LOCAL_CERTIFICATE := $(cert_dir)/ec-p256
include $(BUILD_CTS_SUPPORT_PACKAGE)
cert_dir :=
-
diff --git a/hostsidetests/blobstore/OWNERS b/hostsidetests/blobstore/OWNERS
index bf870975..3a47c48 100644
--- a/hostsidetests/blobstore/OWNERS
+++ b/hostsidetests/blobstore/OWNERS
@@ -1,2 +1,2 @@
-# Bug component: 95221
+# Bug component: 533114
include platform/frameworks/base:/apex/blobstore/OWNERS
diff --git a/hostsidetests/classloaders/useslibrary/app/src/com/android/cts/useslibrary/UsesLibraryTest.java b/hostsidetests/classloaders/useslibrary/app/src/com/android/cts/useslibrary/UsesLibraryTest.java
index 7f8f53e..7fdf2dc 100644
--- a/hostsidetests/classloaders/useslibrary/app/src/com/android/cts/useslibrary/UsesLibraryTest.java
+++ b/hostsidetests/classloaders/useslibrary/app/src/com/android/cts/useslibrary/UsesLibraryTest.java
@@ -47,7 +47,8 @@
}
/**
- * Verify that we punt to run from apk when the shared libraries are missing.
+ * Verify that we still use an oat file (backed by a vdex-only file) when the shared
+ * libraries are missing.
*/
public void testMissingLibrary() throws Exception {
ClassLoader loader = getClass().getClassLoader();
@@ -59,12 +60,13 @@
assertTrue(testDexElements != null && testDexElements.length == 1);
DexFile testDexFile = getDexFileFromDexElement(testDexElements[0]);
- assertFalse(isDexFileBackedByOatFile(testDexFile));
+ assertTrue(isDexFileBackedByOatFile(testDexFile));
}
}
/**
- * Verify that we punt to run from apk if the classpath generates a class collision failure.
+ * Verify that we still use an oat file (backed by a vdex-only file) if the classpath generates
+ * a class collision failure.
*/
public void testDuplicateLibrary() throws Exception {
ClassLoader loader = getClass().getClassLoader();
@@ -87,7 +89,7 @@
assertEquals(Arrays.toString(testDexElements), 2, testDexElements.length);
DexFile testDexFile = getDexFileFromDexElement(testDexElements[1]);
- assertFalse(isDexFileBackedByOatFile(testDexFile));
+ assertTrue(isDexFileBackedByOatFile(testDexFile));
}
}
diff --git a/hostsidetests/compilation/src/android/compilation/cts/AdbRootDependentCompilationTest.java b/hostsidetests/compilation/src/android/compilation/cts/AdbRootDependentCompilationTest.java
index 56a50ca..9e453af6 100644
--- a/hostsidetests/compilation/src/android/compilation/cts/AdbRootDependentCompilationTest.java
+++ b/hostsidetests/compilation/src/android/compilation/cts/AdbRootDependentCompilationTest.java
@@ -127,8 +127,28 @@
if (!canRunTest(EnumSet.noneOf(ProfileLocation.class))) {
return;
}
+
+ // Ensure no profile is initially present.
+ for (ProfileLocation profileLocation : ProfileLocation.values()) {
+ String clientPath = profileLocation.getPath();
+ if (doesFileExist(clientPath)) {
+ executeSuShellAdbCommand(0, "rm", clientPath);
+ }
+ }
+
+ // Copy the profile to the reference location so that the bg-dexopt
+ // can actually do work if it's configured to speed-profile.
+ for (ProfileLocation profileLocation : EnumSet.of(ProfileLocation.REF)) {
+ writeProfile(profileLocation);
+ }
+
// Usually "interpret-only"
String expectedInstallFilter = Objects.requireNonNull(mDevice.getProperty("pm.dexopt.install"));
+ if (expectedInstallFilter.equals("speed-profile")) {
+ // If the filter is speed-profile but no profile is present, the compiler
+ // will change it to verify.
+ expectedInstallFilter = "verify";
+ }
// Usually "speed-profile"
String expectedBgDexoptFilter = Objects.requireNonNull(mDevice.getProperty("pm.dexopt.bg-dexopt"));
@@ -170,16 +190,17 @@
}
public void testCompile_refProfile() throws Exception {
- compileWithProfilesAndCheckFilter(false /* expectOdexChange */,
+ compileWithProfilesAndCheckFilter(true /* expectOdexChange */,
EnumSet.of(ProfileLocation.REF));
- // We assume that the compiler isn't smart enough to realize that the
- // previous odex was compiled before the ref profile was in place, even
- // though theoretically it could be.
+ // expect a change in odex because the of the change form
+ // verify -> speed-profile
}
public void testCompile_curAndRefProfile() throws Exception {
- compileWithProfilesAndCheckFilter(false /* expectOdexChange */,
+ compileWithProfilesAndCheckFilter(true /* expectOdexChange */,
EnumSet.of(ProfileLocation.CUR, ProfileLocation.REF));
+ // expect a change in odex because the of the change form
+ // verify -> speed-profile
}
private byte[] readFileOnClient(String clientPath) throws Exception {
@@ -226,7 +247,9 @@
// Confirm the compiler-filter used in creating the odex file
String compilerFilter = getCompilerFilter(odexFilePath);
- assertEquals("compiler-filter", "speed-profile", compilerFilter);
+ // Without profiles, the compiler filter should be verify.
+ String expectedCompilerFilter = profileLocations.isEmpty() ? "verify" : "speed-profile";
+ assertEquals("compiler-filter", expectedCompilerFilter, compilerFilter);
byte[] odexFileContents = readFileOnClient(odexFilePath);
boolean odexChanged = !(Arrays.equals(initialOdexFileContents, odexFileContents));
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionsParentTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionsParentTest.java
index 9bb371b..a36bd00 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionsParentTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/UserRestrictionsParentTest.java
@@ -20,13 +20,17 @@
import static com.google.common.truth.Truth.assertThat;
+import android.app.UiAutomation;
import android.app.admin.DevicePolicyManager;
+import android.content.ContentResolver;
import android.content.Context;
import android.hardware.camera2.CameraManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.test.InstrumentationTestCase;
import android.util.Log;
@@ -34,18 +38,22 @@
import java.util.concurrent.TimeUnit;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
public class UserRestrictionsParentTest extends InstrumentationTestCase {
private static final String TAG = "UserRestrictionsParentTest";
protected Context mContext;
+ private ContentResolver mContentResolver;
+ private UiAutomation mUiAutomation;
private DevicePolicyManager mDevicePolicyManager;
private UserManager mUserManager;
private CameraManager mCameraManager;
private HandlerThread mBackgroundThread;
+ private static final long GET_UIAUTOMATION_TIMEOUT_NS = TimeUnit.SECONDS.toNanos(60);
/**
* A {@link Handler} for running tasks in the background.
@@ -56,6 +64,8 @@
protected void setUp() throws Exception {
super.setUp();
mContext = getInstrumentation().getContext();
+ mContentResolver = mContext.getContentResolver();
+ mUiAutomation = getUiAutomation();
mDevicePolicyManager = (DevicePolicyManager)
mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
@@ -72,10 +82,23 @@
@Override
protected void tearDown() throws Exception {
+ mUiAutomation.dropShellPermissionIdentity();
stopBackgroundThread();
super.tearDown();
}
+ private UiAutomation getUiAutomation() throws InterruptedException {
+ final long deadline = System.nanoTime() + GET_UIAUTOMATION_TIMEOUT_NS;
+ while (System.nanoTime() < deadline) {
+ UiAutomation ui = getInstrumentation().getUiAutomation();
+ if (ui != null) {
+ return ui;
+ }
+ Thread.sleep(1000);
+ }
+ throw new AssertionError("Failed to get UiAutomation");
+ }
+
public void testAddUserRestrictionDisallowConfigDateTime_onParent() {
DevicePolicyManager parentDevicePolicyManager =
mDevicePolicyManager.getParentProfileInstance(ADMIN_RECEIVER_COMPONENT);
@@ -192,11 +215,18 @@
// UserManager.DISALLOW_DEBUGGING_FEATURES
);
- public void testPerProfileUserRestriction_onParent() {
+ public void testPerProfileUserRestriction_onParent() throws Settings.SettingNotFoundException {
+ mUiAutomation.adoptShellPermissionIdentity(
+ "android.permission.INTERACT_ACROSS_USERS_FULL",
+ "android.permission.CREATE_USERS");
+
DevicePolicyManager parentDevicePolicyManager =
mDevicePolicyManager.getParentProfileInstance(ADMIN_RECEIVER_COMPONENT);
assertNotNull(parentDevicePolicyManager);
+ int locationMode = Settings.Secure.getIntForUser(mContentResolver,
+ Settings.Secure.LOCATION_MODE, UserHandle.USER_SYSTEM);
+
for (String restriction : PROFILE_OWNER_ORGANIZATION_OWNED_LOCAL_RESTRICTIONS) {
try {
boolean hasRestrictionOnManagedProfile = mUserManager.hasUserRestriction(
@@ -214,6 +244,12 @@
assertThat(hasUserRestriction(restriction)).isFalse();
}
}
+
+ // Restore the location mode setting after adding and removing the
+ // DISALLOW_SHARE_LOCATION user restriction. This is because, modifying this user
+ // restriction causes the location mode setting to be turned off.
+ Settings.Secure.putIntForUser(mContentResolver, Settings.Secure.LOCATION_MODE, locationMode,
+ UserHandle.USER_SYSTEM);
}
private static final Set<String> PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS =
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/systemupdate/InstallUpdateTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/systemupdate/InstallUpdateTest.java
old mode 100644
new mode 100755
index 3a3a357..205218d
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/systemupdate/InstallUpdateTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/systemupdate/InstallUpdateTest.java
@@ -206,6 +206,7 @@
&& SystemClock.elapsedRealtime() <= startTime + BATTERY_STATE_CHANGE_TIMEOUT_MS) {
Thread.sleep(BATTERY_STATE_CHANGE_SLEEP_PER_CHECK_MS);
}
+ assertTrue("Battery state update timeout", isBatteryState(plugged, level));
}
private boolean isBatteryState(boolean plugged, int level) {
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/NetworkLoggingTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/NetworkLoggingTest.java
old mode 100644
new mode 100755
index 1856d2c3..0224ba8
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/NetworkLoggingTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/NetworkLoggingTest.java
@@ -274,7 +274,7 @@
private void verifyNetworkLogs(List<NetworkEvent> networkEvents, int eventsExpected) {
// allow a batch to be slightly smaller or larger.
- assertTrue(Math.abs(eventsExpected - networkEvents.size()) <= 50);
+ assertTrue(Math.abs(eventsExpected - networkEvents.size()) <= 150);
int ctsPackageNameCounter = 0;
// allow a small down margin for verification, to avoid flakiness
final int eventsExpectedWithMargin = eventsExpected - 50;
diff --git a/hostsidetests/dexmetadata/host/src/com/android/cts/dexmetadata/InstallDexMetadataHostTest.java b/hostsidetests/dexmetadata/host/src/com/android/cts/dexmetadata/InstallDexMetadataHostTest.java
index ad6aef8..ed52b9f 100644
--- a/hostsidetests/dexmetadata/host/src/com/android/cts/dexmetadata/InstallDexMetadataHostTest.java
+++ b/hostsidetests/dexmetadata/host/src/com/android/cts/dexmetadata/InstallDexMetadataHostTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -201,26 +202,114 @@
assertTrue(runDeviceTests(TEST_PACKAGE, TEST_CLASS, "testDmForBaseButNoSplit"));
}
- static class ProfileReader {
- byte[] data;
+ static class ProfileReaderV10 {
+ byte[] data;
- ProfileReader(byte[] bytes) throws Exception {
- ByteBuffer bb = ByteBuffer.wrap(bytes);
+ ProfileReaderV10(byte[] bytes) throws Exception {
+ ByteBuffer bb = ByteBuffer.wrap(bytes);
- // Read header.
- bb.order(ByteOrder.LITTLE_ENDIAN);
- assertEquals(0x006f7270 /* LE "pro\0" */, bb.getInt());
- assertEquals(0x00303130 /* LE "010\0" */, bb.getInt());
- bb.get(); // Skip dex file count.
- int uncompressed_size = bb.getInt();
- int compressed_size = bb.getInt();
+ // Read header.
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+ assertEquals(0x006f7270 /* LE "pro\0" */, bb.getInt());
+ assertEquals(0x00303130 /* LE "010\0" */, bb.getInt());
+ bb.get(); // Skip dex file count.
+ int uncompressed_size = bb.getInt();
+ int compressed_size = bb.getInt();
- // Decompress profile.
- Inflater inflater = new Inflater();
- inflater.setInput(bb.array(), bb.arrayOffset() + bb.position(), bb.remaining());
- data = new byte[uncompressed_size];
- assertEquals(uncompressed_size, inflater.inflate(data));
- }
+ // Decompress profile.
+ Inflater inflater = new Inflater();
+ inflater.setInput(bb.array(), bb.arrayOffset() + bb.position(), bb.remaining());
+ data = new byte[uncompressed_size];
+ assertEquals(uncompressed_size, inflater.inflate(data));
+ }
+ }
+
+ static class ProfileReaderV13 {
+ byte[] dexFilesData;
+ byte[] extraDescriptorsData;
+ byte[] classesData;
+ byte[] methodsData;
+
+ ProfileReaderV13(byte[] bytes) throws Exception {
+ ByteBuffer bb = ByteBuffer.wrap(bytes);
+
+ // Read header.
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+ assertEquals(0x006f7270 /* LE "pro\0" */, bb.getInt());
+ assertEquals(0x00333130 /* LE "013\0" */, bb.getInt());
+ int section_count = bb.getInt();
+ assertFalse(section_count == 0);
+
+ // Mandatory dex files section.
+ assertEquals(/*kDexFiles*/ 0, bb.getInt());
+ dexFilesData = readSection(bb);
+
+ // Read optional sections. Assume no more than one occurrence of each known section.
+ for (int i = 1; i != section_count; ++i) {
+ int sectionType = bb.getInt();
+ switch (sectionType) {
+ case 1: // kExtraDescriptors
+ assertTrue(extraDescriptorsData == null);
+ extraDescriptorsData = readSection(bb);
+ break;
+ case 2: // kClasses
+ assertTrue(classesData == null);
+ classesData = readSection(bb);
+ break;
+ case 3: // kMethods
+ assertTrue(methodsData == null);
+ methodsData = readSection(bb);
+ break;
+ default:
+ // Unknown section. Skip it. New versions of ART are allowed
+ // to add sections that shall be ignored by old versions.
+ skipSection(bb);
+ break;
+ }
+ }
+ }
+
+ private byte[] readSection(ByteBuffer bb) throws Exception {
+ int fileOffset = bb.getInt();
+ int fileSize = bb.getInt();
+ int inflatedSize = bb.getInt();
+ if (inflatedSize != 0) {
+ // Decompress section.
+ byte[] data = new byte[inflatedSize];
+ Inflater inflater = new Inflater();
+ inflater.setInput(bb.array(), fileOffset, fileSize);
+ assertEquals(inflatedSize, inflater.inflate(data));
+ return data;
+ } else {
+ // Copy uncompressed data.
+ byte[] data = new byte[fileSize];
+ System.arraycopy(bb.array(), fileOffset, data, 0, fileSize);
+ return data;
+ }
+ }
+
+ private void skipSection(ByteBuffer bb) {
+ bb.getInt(); // fileOffset
+ bb.getInt(); // fileSize
+ bb.getInt(); // inflatedSize
+ }
+ }
+
+ private static int getProfileVersion(byte[] bytes) {
+ assertEquals(bytes[0], (byte) 'p');
+ assertEquals(bytes[1], (byte) 'r');
+ assertEquals(bytes[2], (byte) 'o');
+ assertEquals(bytes[3], (byte) '\0');
+ assertEquals(bytes[7], (byte) '\0');
+ int version = 0;
+ for (int pos = 4; pos != 7; ++pos) {
+ byte digit = bytes[pos];
+ if (digit < (byte) '0' || digit > (byte) '9') {
+ throw new Error("Non-numeric profile version");
+ }
+ version = version * 10 + (((int) digit) - '0');
+ }
+ return version;
}
@Test
@@ -236,11 +325,28 @@
assertTrue(result.trim().isEmpty());
// Extract the profile bytes from the dex metadata and from the profile snapshot.
- byte[] snapshotProfileBytes = new ProfileReader(extractProfileSnapshotFromDevice()).data;
- byte[] expectedProfileBytes =
- new ProfileReader(extractProfileFromDexMetadata(mDmBaseFile)).data;
+ byte[] rawDeviceProfile = extractProfileSnapshotFromDevice();
+ int deviceProfileVersion = getProfileVersion(rawDeviceProfile);
+ switch (deviceProfileVersion) {
+ case 10: {
+ byte[] snapshotProfileBytes = new ProfileReaderV10(rawDeviceProfile).data;
+ byte[] expectedProfileBytes =
+ new ProfileReaderV10(extractProfileFromDexMetadata(mDmBaseFile)).data;
- assertArrayEquals(expectedProfileBytes, snapshotProfileBytes);
+ assertArrayEquals(expectedProfileBytes, snapshotProfileBytes);
+ break;
+ }
+ case 13: {
+ ProfileReaderV13 reader = new ProfileReaderV13(rawDeviceProfile);
+ // TODO: Support newer profiles implemented for b/148067697.
+ // Currently the .dm file is still version 10, so we cannot compare against it.
+ System.out.println("TODO: Check profile version 13.");
+ break;
+ }
+ default: {
+ throw new Error("Unsupported profile version: " + deviceProfileVersion);
+ }
+ }
}
/**
diff --git a/hostsidetests/edi/Android.bp b/hostsidetests/edi/Android.bp
index d542654..80a7cc6 100644
--- a/hostsidetests/edi/Android.bp
+++ b/hostsidetests/edi/Android.bp
@@ -25,8 +25,15 @@
"general-tests",
],
libs: [
- "cts-tradefed",
- "tradefed",
"compatibility-host-util",
+ "cts-tradefed",
+ "dexlib2-no-guava-no-cli",
+ "tradefed",
+ ],
+ static_libs: [
+ "compat-classpaths-testing",
+ ],
+ data: [
+ ":ClasspathDeviceInfoHelperApp",
],
}
diff --git a/hostsidetests/edi/AndroidTest.xml b/hostsidetests/edi/AndroidTest.xml
index acd6b57..c39246f 100644
--- a/hostsidetests/edi/AndroidTest.xml
+++ b/hostsidetests/edi/AndroidTest.xml
@@ -20,6 +20,10 @@
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="ClasspathDeviceInfoHelperApp.apk" />
+ </target_preparer>
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsEdiHostTestCases.jar" />
</test>
diff --git a/hostsidetests/edi/apps/classpath/Android.bp b/hostsidetests/edi/apps/classpath/Android.bp
new file mode 100644
index 0000000..3b1626e
--- /dev/null
+++ b/hostsidetests/edi/apps/classpath/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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: "ClasspathDeviceInfoHelperApp",
+ defaults: ["cts_defaults"],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.core",
+ "guava",
+ ],
+ srcs: ["src/**/*.java"],
+ sdk_version: "test_current",
+}
diff --git a/hostsidetests/edi/apps/classpath/AndroidManifest.xml b/hostsidetests/edi/apps/classpath/AndroidManifest.xml
new file mode 100644
index 0000000..88cb689
--- /dev/null
+++ b/hostsidetests/edi/apps/classpath/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.edi.cts.apps.classpath"
+ android:targetSandboxVersion="2">
+
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.ACCESS_SHARED_LIBRARIES" />
+
+ <application android:requestLegacyExternalStorage="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.edi.cts.apps.classpath" />
+
+</manifest>
diff --git a/hostsidetests/edi/apps/classpath/src/android/edi/cts/apps/classpath/ClasspathDeviceTest.java b/hostsidetests/edi/apps/classpath/src/android/edi/cts/apps/classpath/ClasspathDeviceTest.java
new file mode 100644
index 0000000..93532aa
--- /dev/null
+++ b/hostsidetests/edi/apps/classpath/src/android/edi/cts/apps/classpath/ClasspathDeviceTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.edi.cts.apps.classpath;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.pm.SharedLibraryInfo;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Device-side helper app for ClasspathDeviceInfo.
+ *
+ * <p>It is not technically a test as it simply collects information, but it simplifies the usage
+ * and communication with host-side ClasspathDeviceInfo.
+ */
+@RunWith(AndroidJUnit4.class)
+public class ClasspathDeviceTest {
+
+ private static final String TAG = "ClasspathDeviceTest";
+
+ private final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ private final Context context = instrumentation.getTargetContext();
+
+ @Before
+ public void before() {
+ instrumentation.getUiAutomation().adoptShellPermissionIdentity();
+ }
+
+ @After
+ public void after() {
+ instrumentation.getUiAutomation().dropShellPermissionIdentity();
+ }
+
+ /**
+ * Collects details about all shared libraries on the device and writes them to disk.
+ */
+ @Test
+ public void collectSharedLibraryPaths() throws Exception {
+ List<SharedLibraryInfo> sharedLibraries =
+ context.getPackageManager().getSharedLibraries(0);
+
+ ImmutableList.Builder<String> content = ImmutableList.builder();
+ for (SharedLibraryInfo sharedLibrary : sharedLibraries) {
+ content.add(String.format(Locale.US, "%s %d %d %s",
+ sharedLibrary.getName(),
+ sharedLibrary.getType(),
+ sharedLibrary.getLongVersion(),
+ String.join(" ", sharedLibrary.getAllCodePaths())));
+ }
+
+ Path detailsFilepath = new File("/sdcard/shared-libs.txt").toPath();
+ ImmutableList<String> lines = content.build();
+ Log.i(TAG, String.format("Writing details about %d shared libraries to %s",
+ lines.size(), detailsFilepath));
+ Files.write(detailsFilepath, lines);
+ }
+
+}
diff --git a/hostsidetests/edi/src/android/edi/cts/ClasspathDeviceInfo.java b/hostsidetests/edi/src/android/edi/cts/ClasspathDeviceInfo.java
new file mode 100644
index 0000000..8dc7b32
--- /dev/null
+++ b/hostsidetests/edi/src/android/edi/cts/ClasspathDeviceInfo.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.edi.cts;
+
+import static android.compat.testing.Classpaths.ClasspathType.BOOTCLASSPATH;
+import static android.compat.testing.Classpaths.ClasspathType.DEX2OATBOOTCLASSPATH;
+import static android.compat.testing.Classpaths.ClasspathType.SYSTEMSERVERCLASSPATH;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.compat.testing.Classpaths;
+import android.compat.testing.Classpaths.ClasspathType;
+
+import com.android.compatibility.common.util.DeviceInfo;
+import com.android.compatibility.common.util.HostInfoStore;
+import com.android.tradefed.device.ITestDevice;
+
+import com.google.common.collect.ImmutableList;
+
+import org.jf.dexlib2.iface.ClassDef;
+
+/**
+ * Collects information about Java classes present in *CLASSPATH variables and Java shared libraries
+ * from the device.
+ */
+public class ClasspathDeviceInfo extends DeviceInfo {
+
+ private static final String HELPER_APP_PACKAGE = "android.edi.cts.apps.classpath";
+ private static final String HELPER_APP_CLASS = HELPER_APP_PACKAGE + ".ClasspathDeviceTest";
+
+ private ITestDevice mDevice;
+
+ @Override
+ protected void collectDeviceInfo(HostInfoStore store) throws Exception {
+ mDevice = getDevice();
+
+ store.startArray("jars");
+ collectBootclasspathJars(store);
+ collectSharedLibraryJars(store);
+ store.endArray();
+ }
+
+ private void collectBootclasspathJars(HostInfoStore store) throws Exception {
+ collectClasspathJarInfo(store, BOOTCLASSPATH);
+ collectClasspathJarInfo(store, SYSTEMSERVERCLASSPATH);
+ collectClasspathJarInfo(store, DEX2OATBOOTCLASSPATH);
+ }
+
+ private void collectClasspathJarInfo(HostInfoStore store, ClasspathType classpath)
+ throws Exception {
+ ImmutableList<String> paths = Classpaths.getJarsOnClasspath(mDevice, classpath);
+ for (int i = 0; i < paths.size(); i++) {
+ store.startGroup();
+ store.addResult("classpath", classpath.name());
+ store.addResult("path", paths.get(i));
+ store.addResult("index", i);
+ collectClassInfo(store, paths.get(i));
+ store.endGroup();
+ }
+ }
+
+ private void collectSharedLibraryJars(HostInfoStore store) throws Exception {
+ // Trigger helper app to collect and write info about shared libraries on the device.
+ assertThat(runDeviceTests(HELPER_APP_PACKAGE, HELPER_APP_CLASS)).isTrue();
+
+ String remoteFile = "/sdcard/shared-libs.txt";
+ String content;
+ try {
+ content = mDevice.pullFileContents(remoteFile);
+ } finally {
+ mDevice.deleteFile(remoteFile);
+ }
+
+ for (String line : content.split("\n")) {
+ String[] words = line.split(" ");
+ assertWithMessage(
+ "expected each line to be in the format: <name> <type> <version> <path>...")
+ .that(words.length)
+ .isAtLeast(4);
+ String libraryName = words[0];
+ String libraryType = words[1];
+ String libraryVersion = words[2];
+ for (int i = 3; i < words.length; i++) {
+ String path = words[i];
+
+ store.startGroup();
+ store.startGroup("shared_library");
+ store.addResult("name", libraryName);
+ store.addResult("type", libraryType);
+ store.addResult("version", libraryVersion);
+ store.endGroup(); // shared_library
+ store.addResult("path", path);
+ store.addResult("index", i - 3); // minus <name> <type> <version>
+ collectClassInfo(store, path);
+ store.endGroup();
+ }
+ }
+ }
+
+ private void collectClassInfo(HostInfoStore store, String path) throws Exception {
+ store.startArray("classes");
+ for (ClassDef classDef : Classpaths.getClassDefsFromJar(mDevice, path)) {
+ store.startGroup();
+ store.addResult("name", classDef.getType());
+ store.endGroup();
+ }
+ store.endArray();
+ }
+}
diff --git a/hostsidetests/edi/src/android/edi/cts/PropertyDeviceInfo.java b/hostsidetests/edi/src/android/edi/cts/PropertyDeviceInfo.java
new file mode 100644
index 0000000..b9f6ea1
--- /dev/null
+++ b/hostsidetests/edi/src/android/edi/cts/PropertyDeviceInfo.java
@@ -0,0 +1,78 @@
+/*
+ * 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.edi.cts;
+
+import com.android.compatibility.common.util.DeviceInfo;
+import com.android.compatibility.common.util.HostInfoStore;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.util.CommandResult;
+
+import java.util.Scanner;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * System property info collector.
+ */
+public class PropertyDeviceInfo extends DeviceInfo {
+
+ @Override
+ protected void collectDeviceInfo(HostInfoStore store) throws Exception {
+ store.startArray("ro_property");
+ try {
+ ITestDevice device = getDevice();
+ CommandResult commandResult = device.executeShellV2Command("getprop");
+ if (commandResult.getExitCode() == null) {
+ CLog.e("getprop exit code is null");
+ return;
+ }
+ if (commandResult.getExitCode() != 0) {
+ CLog.e("getprop returns %d: %s", commandResult.getExitCode(),
+ commandResult.getStderr());
+ return;
+ }
+ if (commandResult.getExitCode() == 0 && !commandResult.getStderr().isEmpty()) {
+ CLog.w("Warnings occur when running getprop:\n%s",
+ commandResult.getStderr());
+ }
+
+ parseProps(commandResult.getStdout(), store);
+ } finally {
+ store.endArray();
+ }
+ }
+
+ private void parseProps(String stdout, HostInfoStore store) throws Exception {
+ Pattern pattern = Pattern.compile("\\[(ro.+)\\]: \\[(.+)\\]");
+ if (stdout == null) stdout = "";
+ try (Scanner scanner = new Scanner(stdout)) {
+ while (scanner.hasNextLine()) {
+ String line = scanner.nextLine();
+ Matcher matcher = pattern.matcher(line);
+ if (matcher.matches()) {
+ String name = matcher.group(1);
+ String value = matcher.group(2);
+
+ store.startGroup();
+ store.addResult("name", name);
+ store.addResult("value", value);
+ store.endGroup();
+ }
+ }
+ }
+ }
+}
diff --git a/hostsidetests/hdmicec/README.md b/hostsidetests/hdmicec/README.md
index db02090..b774e46 100644
--- a/hostsidetests/hdmicec/README.md
+++ b/hostsidetests/hdmicec/README.md
@@ -17,14 +17,42 @@
* Android TV playback device
* CEC adapter, see [External CEC Adapter instructions](cec_adapter.md)
* Install `cec-client` binary, see [install instructions](cec_adapter.md#software)
-* HDMI Display (aka a TV) or an HDMI fake plug
+* HDMI Display (aka a TV) with CEC disabled to avoid interference, or an HDMI fake plug
+
+It is recommended that the playback device has an HDMI physical address of `1.0.0.0` while running
+the tests. In case the DUT takes a physical address other than `1.0.0.0` and this is unavoidable,
+the tests can be configured to expect a different physical address by appending these arguments to
+the tradefed command:
+```
+--module-arg CtsHdmiCecHostTestCases:set-option:cec-phy-addr:<address_in_decimal>
+```
+Thus, for a device that is taking an address `3.0.0.0`, pass `12288` as the `cec-phy-addr` argument.
+
+The CEC adapter may also be installed in-between the TV and the playback device.

+### TV panel devices
+
+Running these CTS tests on TV panel devices requires an external CEC adapter.
+
+* Android TV panel device
+* CEC adapter, see [External CEC Adapter instructions](cec_adapter.md)
+* Install `cec-client` binary, see [install instructions](cec_adapter.md#software)
+
+It is recommended to connect the CEC adapter to the HDMI ARC port of the TV device.
+
### Automation
-Given the setup described above you can run all of these tests with the command
+Given the setup described above you can run this test module with the following commands:
+#### cts-tradefed
+
+```
+cts-tradefed > run cts -m CtsHdmiCecHostTestCases
+```
+
+#### atest
```
atest CtsHdmiCecHostTestCases
```
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/BaseHdmiCecCtsTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/BaseHdmiCecCtsTest.java
index 2b6b6d1..853510b 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/BaseHdmiCecCtsTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/BaseHdmiCecCtsTest.java
@@ -16,8 +16,11 @@
package android.hdmicec.cts;
+import android.hdmicec.cts.error.DumpsysParseException;
+
import com.android.tradefed.config.Option;
import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
@@ -25,6 +28,7 @@
import org.junit.rules.TestRule;
import java.io.BufferedReader;
+import java.io.IOException;
import java.io.StringReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -33,6 +37,25 @@
@OptionClass(alias="hdmi-cec-client-cts-test")
public class BaseHdmiCecCtsTest extends BaseHostJUnit4Test {
+ public static final String PROPERTY_LOCALE = "persist.sys.locale";
+
+ /** Enum contains the list of possible address types. */
+ private enum AddressType {
+ DUMPSYS_LOGICAL_ADDRESS("logicalAddress"),
+ DUMPSYS_AS_LOGICAL_ADDRESS("activeSourceLogicalAddress"),
+ DUMPSYS_PHYSICAL_ADDRESS("physicalAddress");
+
+ private String address;
+
+ public String getAddressType() {
+ return this.address;
+ }
+
+ private AddressType(String address) {
+ this.address = address;
+ }
+ }
+
public final HdmiCecClientWrapper hdmiCecClient;
public LogicalAddress mDutLogicalAddress;
@@ -108,85 +131,114 @@
public static int dutPhysicalAddress = HdmiCecConstants.DEFAULT_PHYSICAL_ADDRESS;
/** Gets the physical address of the DUT by parsing the dumpsys hdmi_control. */
- public int getDumpsysPhysicalAddress() throws Exception {
+ public int getDumpsysPhysicalAddress() throws DumpsysParseException {
return getDumpsysPhysicalAddress(getDevice());
}
/** Gets the physical address of the specified device by parsing the dumpsys hdmi_control. */
- public static int getDumpsysPhysicalAddress(ITestDevice device) throws Exception {
- String line;
- String pattern = "(.*?)" + "(physical_address: )" + "(?<address>0x\\p{XDigit}{4})" +
- "(.*?)";
- Pattern p = Pattern.compile(pattern);
- Matcher m;
- String dumpsys = device.executeShellCommand("dumpsys hdmi_control");
- BufferedReader reader = new BufferedReader(new StringReader(dumpsys));
- while ((line = reader.readLine()) != null) {
- m = p.matcher(line);
- if (m.matches()) {
- int address = Integer.decode(m.group("address"));
- return address;
- }
- }
- throw new Exception("Could not parse physical address from dumpsys.");
+ public static int getDumpsysPhysicalAddress(ITestDevice device) throws DumpsysParseException {
+ return parseRequiredAddressFromDumpsys(device, AddressType.DUMPSYS_PHYSICAL_ADDRESS);
}
/** Gets the logical address of the DUT by parsing the dumpsys hdmi_control. */
- public int getDumpsysLogicalAddress() throws Exception {
+ public int getDumpsysLogicalAddress() throws DumpsysParseException {
return getDumpsysLogicalAddress(getDevice());
}
/** Gets the logical address of the specified device by parsing the dumpsys hdmi_control. */
- public static int getDumpsysLogicalAddress(ITestDevice device) throws Exception {
- String line;
- String pattern = "(.*?)" + "(mAddress: )" + "(?<address>\\d+)" +
- "(.*?)";
- Pattern p = Pattern.compile(pattern);
- Matcher m;
- String dumpsys = device.executeShellCommand("dumpsys hdmi_control");
- BufferedReader reader = new BufferedReader(new StringReader(dumpsys));
- while ((line = reader.readLine()) != null) {
- m = p.matcher(line);
- if (m.matches()) {
- int address = Integer.decode(m.group("address"));
- return address;
- }
- }
- throw new Exception("Could not parse logical address from dumpsys.");
+ public static int getDumpsysLogicalAddress(ITestDevice device) throws DumpsysParseException {
+ return parseRequiredAddressFromDumpsys(device, AddressType.DUMPSYS_LOGICAL_ADDRESS);
}
/**
* Parses the dumpsys hdmi_control to get the logical address of the current device registered
* as active source.
*/
- public LogicalAddress getDumpsysActiveSourceLogicalAddress() throws Exception {
- String line;
- String pattern =
- "(.*?)"
- + "(mActiveSource: )"
- + "(\\(0x)"
- + "(?<logicalAddress>\\d+)"
- + "(, )"
- + "(0x)"
- + "(?<physicalAddress>\\d+)"
- + "(\\))"
- + "(.*?)";
- Pattern p = Pattern.compile(pattern);
- Matcher m;
+ public LogicalAddress getDumpsysActiveSourceLogicalAddress() throws DumpsysParseException {
ITestDevice device = getDevice();
- String dumpsys = device.executeShellCommand("dumpsys hdmi_control");
- BufferedReader reader = new BufferedReader(new StringReader(dumpsys));
- while ((line = reader.readLine()) != null) {
- m = p.matcher(line);
- if (m.matches()) {
- try {
- int address = Integer.decode(m.group("logicalAddress"));
- return LogicalAddress.getLogicalAddress(address);
- } catch (NumberFormatException ne) {
- throw new Exception("Could not correctly parse the logical address");
+ int address =
+ parseRequiredAddressFromDumpsys(device, AddressType.DUMPSYS_AS_LOGICAL_ADDRESS);
+ return LogicalAddress.getLogicalAddress(address);
+ }
+
+ private static int parseRequiredAddressFromDumpsys(ITestDevice device, AddressType addressType)
+ throws DumpsysParseException {
+ Matcher m;
+ String line;
+ String pattern;
+ switch (addressType) {
+ case DUMPSYS_LOGICAL_ADDRESS:
+ pattern =
+ "(.*?)"
+ + "(mAddress: )"
+ + "(?<"
+ + addressType.getAddressType()
+ + ">\\p{XDigit}{1})"
+ + "(.*?)";
+ break;
+ case DUMPSYS_PHYSICAL_ADDRESS:
+ pattern =
+ "(.*?)"
+ + "(physical_address: )"
+ + "(?<"
+ + addressType.getAddressType()
+ + ">0x\\p{XDigit}{4})"
+ + "(.*?)";
+ break;
+ case DUMPSYS_AS_LOGICAL_ADDRESS:
+ pattern =
+ "(.*?)"
+ + "(mActiveSource: )"
+ + "(\\(0x)"
+ + "(?<"
+ + addressType.getAddressType()
+ + ">\\d+)"
+ + "(, )"
+ + "(0x)"
+ + "(?<physicalAddress>\\d+)"
+ + "(\\))"
+ + "(.*?)";
+ break;
+ default:
+ throw new DumpsysParseException(
+ "Incorrect parameters", new IllegalArgumentException());
+ }
+
+ try {
+ Pattern p = Pattern.compile(pattern);
+ String dumpsys = device.executeShellCommand("dumpsys hdmi_control");
+ BufferedReader reader = new BufferedReader(new StringReader(dumpsys));
+ while ((line = reader.readLine()) != null) {
+ m = p.matcher(line);
+ if (m.matches()) {
+ int address = Integer.decode(m.group(addressType.getAddressType()));
+ return address;
}
}
+ } catch (IOException | DeviceNotAvailableException e) {
+ throw new DumpsysParseException(
+ "Could not parse " + addressType.getAddressType() + " from dumpsys.", e);
}
- throw new Exception("Could not parse active source from dumpsys.");
+ throw new DumpsysParseException(
+ "Could not parse " + addressType.getAddressType() + " from dumpsys.");
+ }
+
+ public String getSystemLocale() throws Exception {
+ ITestDevice device = getDevice();
+ return device.executeShellCommand("getprop " + PROPERTY_LOCALE).trim();
+ }
+
+ public static String extractLanguage(String locale) {
+ return locale.split("[^a-zA-Z]")[0];
+ }
+
+ public void setSystemLocale(String locale) throws Exception {
+ ITestDevice device = getDevice();
+ device.executeShellCommand("setprop " + PROPERTY_LOCALE + " " + locale);
+ }
+
+ public boolean isLanguageEditable() throws Exception {
+ String val = getDevice().executeShellCommand("getprop ro.hdmi.set_menu_language");
+ return val.trim().equals("true") ? true : false;
}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecOperand.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecOperand.java
index f04a1a7..f3b50b1 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecOperand.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecOperand.java
@@ -53,6 +53,7 @@
REQUEST_SHORT_AUDIO_DESCRIPTOR(0xa4),
INITIATE_ARC(0xc0),
ARC_INITIATED(0xc1),
+ ARC_TERMINATED(0xc2),
REQUEST_ARC_INITIATION(0xc3),
REQUEST_ARC_TERMINATION(0xc4),
TERMINATE_ARC(0xc5),
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
index 39cadcb..9d8849f 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
@@ -16,6 +16,10 @@
package android.hdmicec.cts;
+import android.hdmicec.cts.error.ErrorCodes;
+import android.hdmicec.cts.error.CecClientWrapperException;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.util.RunUtil;
@@ -69,7 +73,7 @@
targetDevice = dutLogicalAddress;
}
- public List<String> getValidCecClientPorts() throws Exception {
+ public List<String> getValidCecClientPorts() throws CecClientWrapperException {
List<String> listPortsCommand = new ArrayList();
@@ -77,28 +81,40 @@
listPortsCommand.add("-l");
List<String> comPorts = new ArrayList();
- Process cecClient = RunUtil.getDefault().runCmdInBackground(listPortsCommand);
- BufferedReader inputConsole =
- new BufferedReader(new InputStreamReader(cecClient.getInputStream()));
- while (cecClient.isAlive()) {
- if (inputConsole.ready()) {
- String line = inputConsole.readLine();
- if (line.toLowerCase().contains("com port")) {
- String port = line.split(":")[1].trim();
- comPorts.add(port);
+ try {
+ Process cecClient = RunUtil.getDefault().runCmdInBackground(listPortsCommand);
+ BufferedReader inputConsole =
+ new BufferedReader(new InputStreamReader(cecClient.getInputStream()));
+ while (cecClient.isAlive()) {
+ if (inputConsole.ready()) {
+ String line = inputConsole.readLine();
+ if (line.toLowerCase().contains("com port")) {
+ String port = line.split(":")[1].trim();
+ comPorts.add(port);
+ }
}
}
+ inputConsole.close();
+ cecClient.waitFor();
+ } catch (IOException | InterruptedException ioe) {
+ throw new CecClientWrapperException(ErrorCodes.ReadConsole, ioe);
}
- inputConsole.close();
- cecClient.waitFor();
return comPorts;
}
- boolean initValidCecClient(ITestDevice device, List<String> clientCommands) throws Exception {
- String serialNo = device.getProperty("ro.serialno");
- File mDeviceEntry = new File(HdmiCecConstants.CEC_MAP_FOLDER, serialNo);
+ boolean initValidCecClient(ITestDevice device, List<String> clientCommands)
+ throws CecClientWrapperException {
+
+ String serialNo;
List<String> launchCommand = new ArrayList(clientCommands);
+ try {
+ serialNo = device.getProperty("ro.serialno");
+ } catch (DeviceNotAvailableException de) {
+ throw new CecClientWrapperException(ErrorCodes.DeviceNotAvailable, de);
+ }
+ File mDeviceEntry = new File(HdmiCecConstants.CEC_MAP_FOLDER, serialNo);
+
try (BufferedReader reader = new BufferedReader(new FileReader(mDeviceEntry))) {
String port = reader.readLine();
launchCommand.add(port);
@@ -119,17 +135,18 @@
Process killProcess = mCecClient.destroyForcibly();
killProcess.waitFor();
}
- } catch (IOException ioe) {
- throw new Exception("Could not open port mapping file");
+ } catch (IOException | InterruptedException ioe) {
+ throw new CecClientWrapperException(
+ ErrorCodes.ReadConsole, ioe, "Could not open port mapping file");
}
-
return false;
}
/** Initialise the client */
- void init(boolean startAsTv, ITestDevice device) throws Exception {
+ void init(boolean startAsTv, ITestDevice device) throws CecClientWrapperException {
if (targetDevice == LogicalAddress.UNKNOWN) {
- throw new IllegalStateException("Missing logical address of the target device.");
+ throw new CecClientWrapperException(
+ ErrorCodes.CecClientStart, "Missing logical address of the target device.");
}
List<String> commands = new ArrayList();
@@ -155,16 +172,16 @@
if (!initValidCecClient(device, commands)) {
mCecClientInitialised = false;
- throw (new Exception("Could not initialise cec-client process"));
+ throw new CecClientWrapperException(ErrorCodes.CecClientStart);
}
}
- private void checkCecClient() throws Exception {
+ private void checkCecClient() throws CecClientWrapperException {
if (!mCecClientInitialised) {
- throw new Exception("cec-client not initialised!");
+ throw new CecClientWrapperException(ErrorCodes.CecClientStart);
}
if (!mCecClient.isAlive()) {
- throw new Exception("cec-client not running!");
+ throw new CecClientWrapperException(ErrorCodes.CecClientNotRunning);
}
}
@@ -172,7 +189,7 @@
* Sends a CEC message with source marked as broadcast to the device passed in the constructor
* through the output console of the cec-communication channel.
*/
- public void sendCecMessage(CecOperand message) throws Exception {
+ public void sendCecMessage(CecOperand message) throws CecClientWrapperException {
sendCecMessage(LogicalAddress.BROADCAST, targetDevice, message, "");
}
@@ -180,7 +197,8 @@
* Sends a CEC message from source device to the device passed in the constructor through the
* output console of the cec-communication channel.
*/
- public void sendCecMessage(LogicalAddress source, CecOperand message) throws Exception {
+ public void sendCecMessage(LogicalAddress source, CecOperand message)
+ throws CecClientWrapperException {
sendCecMessage(source, targetDevice, message, "");
}
@@ -188,8 +206,9 @@
* Sends a CEC message from source device to a destination device through the output console of
* the cec-communication channel.
*/
- public void sendCecMessage(LogicalAddress source, LogicalAddress destination,
- CecOperand message) throws Exception {
+ public void sendCecMessage(
+ LogicalAddress source, LogicalAddress destination, CecOperand message)
+ throws CecClientWrapperException {
sendCecMessage(source, destination, message, "");
}
@@ -197,7 +216,7 @@
* Broadcasts a CEC ACTIVE_SOURCE message from client device source through the output console
* of the cec-communication channel.
*/
- public void broadcastActiveSource(LogicalAddress source) throws Exception {
+ public void broadcastActiveSource(LogicalAddress source) throws CecClientWrapperException {
int sourcePa = (source == selfDevice) ? physicalAddress : 0xFFFF;
sendCecMessage(
source,
@@ -211,7 +230,7 @@
* source through the output console of the cec-communication channel.
*/
public void broadcastActiveSource(LogicalAddress source, int physicalAddressOfActiveDevice)
- throws Exception {
+ throws CecClientWrapperException {
sendCecMessage(
source,
LogicalAddress.BROADCAST,
@@ -224,7 +243,8 @@
* Broadcasts a CEC REPORT_PHYSICAL_ADDRESS message from client device source through the output
* console of the cec-communication channel.
*/
- public void broadcastReportPhysicalAddress(LogicalAddress source) throws Exception {
+ public void broadcastReportPhysicalAddress(LogicalAddress source)
+ throws CecClientWrapperException {
String deviceType = CecMessage.formatParams(source.getDeviceType());
int sourcePa = (source == selfDevice) ? physicalAddress : 0xFFFF;
String physicalAddress =
@@ -241,7 +261,7 @@
* device source through the output console of the cec-communication channel.
*/
public void broadcastReportPhysicalAddress(LogicalAddress source, int physicalAddressToReport)
- throws Exception {
+ throws CecClientWrapperException {
String deviceType = CecMessage.formatParams(source.getDeviceType());
String physicalAddress =
CecMessage.formatParams(
@@ -257,27 +277,37 @@
* Sends a CEC message from source device to a destination device through the output console of
* the cec-communication channel with the appended params.
*/
- public void sendCecMessage(LogicalAddress source, LogicalAddress destination,
- CecOperand message, String params) throws Exception {
+ public void sendCecMessage(
+ LogicalAddress source, LogicalAddress destination, CecOperand message, String params)
+ throws CecClientWrapperException {
checkCecClient();
String sendMessageString = "tx " + source + destination + ":" + message + params;
- mOutputConsole.write(sendMessageString);
- mOutputConsole.newLine();
- mOutputConsole.flush();
+ try {
+ mOutputConsole.write(sendMessageString);
+ mOutputConsole.newLine();
+ mOutputConsole.flush();
+ } catch (IOException ioe) {
+ throw new CecClientWrapperException(ErrorCodes.WriteConsole, ioe);
+ }
}
/**
- * Sends a <USER_CONTROL_PRESSED> and <USER_CONTROL_RELEASED> from source to destination
- * through the output console of the cec-communication channel with the mentioned keycode.
+ * Sends a <USER_CONTROL_PRESSED> and <USER_CONTROL_RELEASED> from source to destination through
+ * the output console of the cec-communication channel with the mentioned keycode.
*/
- public void sendUserControlPressAndRelease(LogicalAddress source, LogicalAddress destination,
- int keycode, boolean holdKey) throws Exception {
+ public void sendUserControlPressAndRelease(
+ LogicalAddress source, LogicalAddress destination, int keycode, boolean holdKey)
+ throws CecClientWrapperException {
sendUserControlPress(source, destination, keycode, holdKey);
- /* Sleep less than 200ms between press and release */
- TimeUnit.MILLISECONDS.sleep(100);
- mOutputConsole.write("tx " + source + destination + ":" +
- CecOperand.USER_CONTROL_RELEASED);
- mOutputConsole.flush();
+ try {
+ /* Sleep less than 200ms between press and release */
+ TimeUnit.MILLISECONDS.sleep(100);
+ mOutputConsole.write(
+ "tx " + source + destination + ":" + CecOperand.USER_CONTROL_RELEASED);
+ mOutputConsole.flush();
+ } catch (IOException | InterruptedException ioe) {
+ throw new CecClientWrapperException(ErrorCodes.WriteConsole, ioe);
+ }
}
/**
@@ -285,59 +315,76 @@
* cec-communication channel with the mentioned keycode. If holdKey is true, the method will
* send multiple <UCP> messages to simulate a long press. No <UCR> will be sent.
*/
- public void sendUserControlPress(LogicalAddress source, LogicalAddress destination,
- int keycode, boolean holdKey) throws Exception {
+ public void sendUserControlPress(
+ LogicalAddress source, LogicalAddress destination, int keycode, boolean holdKey)
+ throws CecClientWrapperException {
String key = String.format("%02x", keycode);
String command = "tx " + source + destination + ":" +
CecOperand.USER_CONTROL_PRESSED + ":" + key;
- if (holdKey) {
- /* Repeat once between 200ms and 450ms for at least 5 seconds. Since message will be
- * sent once later, send 16 times in loop every 300ms. */
- int repeat = 16;
- for (int i = 0; i < repeat; i++) {
- mOutputConsole.write(command);
- mOutputConsole.newLine();
- mOutputConsole.flush();
- TimeUnit.MILLISECONDS.sleep(300);
+ try {
+ if (holdKey) {
+ /* Repeat once between 200ms and 450ms for at least 5 seconds. Since message will be
+ * sent once later, send 16 times in loop every 300ms. */
+ int repeat = 16;
+ for (int i = 0; i < repeat; i++) {
+ mOutputConsole.write(command);
+ mOutputConsole.newLine();
+ mOutputConsole.flush();
+ TimeUnit.MILLISECONDS.sleep(300);
+ }
}
- }
- mOutputConsole.write(command);
- mOutputConsole.newLine();
- mOutputConsole.flush();
+ mOutputConsole.write(command);
+ mOutputConsole.newLine();
+ mOutputConsole.flush();
+ } catch (IOException | InterruptedException ioe) {
+ throw new CecClientWrapperException(ErrorCodes.WriteConsole, ioe);
+ }
}
/**
* Sends a series of <UCP> [firstKeycode] from source to destination through the output console
* of the cec-communication channel immediately followed by <UCP> [secondKeycode]. No <UCR>
- * message is sent.
+ * message is sent.
*/
public void sendUserControlInterruptedPressAndHold(
- LogicalAddress source, LogicalAddress destination,
- int firstKeycode, int secondKeycode, boolean holdKey) throws Exception {
+ LogicalAddress source,
+ LogicalAddress destination,
+ int firstKeycode,
+ int secondKeycode,
+ boolean holdKey)
+ throws CecClientWrapperException {
sendUserControlPress(source, destination, firstKeycode, holdKey);
- /* Sleep less than 200ms between press and release */
- TimeUnit.MILLISECONDS.sleep(100);
+ try {
+ /* Sleep less than 200ms between press and release */
+ TimeUnit.MILLISECONDS.sleep(100);
+ } catch (InterruptedException ie) {
+ throw new CecClientWrapperException(ErrorCodes.WriteConsole, ie);
+ }
sendUserControlPress(source, destination, secondKeycode, false);
}
/** Sends a message to the output console of the cec-client */
- public void sendConsoleMessage(String message) throws Exception {
+ public void sendConsoleMessage(String message) throws CecClientWrapperException {
checkCecClient();
CLog.v("Sending message:: " + message);
- mOutputConsole.write(message);
- mOutputConsole.flush();
+ try {
+ mOutputConsole.write(message);
+ mOutputConsole.flush();
+ } catch (IOException ioe) {
+ throw new CecClientWrapperException(ErrorCodes.WriteConsole, ioe);
+ }
}
/** Check for any string on the input console of the cec-client, uses default timeout */
- public boolean checkConsoleOutput(String expectedMessage) throws Exception {
+ public boolean checkConsoleOutput(String expectedMessage) throws CecClientWrapperException {
return checkConsoleOutput(expectedMessage, DEFAULT_TIMEOUT);
}
/** Check for any string on the input console of the cec-client */
- public boolean checkConsoleOutput(String expectedMessage,
- long timeoutMillis) throws Exception {
+ public boolean checkConsoleOutput(String expectedMessage, long timeoutMillis)
+ throws CecClientWrapperException {
checkCecClient();
return checkConsoleOutput(expectedMessage, timeoutMillis, mInputConsole);
}
@@ -345,29 +392,36 @@
/** Check for any string on the specified input console */
public boolean checkConsoleOutput(
String expectedMessage, long timeoutMillis, BufferedReader inputConsole)
- throws Exception {
+ throws CecClientWrapperException {
long startTime = System.currentTimeMillis();
long endTime = startTime;
while ((endTime - startTime <= timeoutMillis)) {
- if (inputConsole.ready()) {
- String line = inputConsole.readLine();
- if (line != null && line.toLowerCase().contains(expectedMessage)) {
- CLog.v("Found " + expectedMessage + " in " + line);
- return true;
- } else if (line.toLowerCase().contains(CEC_PORT_BUSY)) {
- throw new CecPortBusyException();
+ try {
+ if (inputConsole.ready()) {
+ String line = inputConsole.readLine();
+ if (line != null
+ && line.toLowerCase().contains(expectedMessage.toLowerCase())) {
+ CLog.v("Found " + expectedMessage + " in " + line);
+ return true;
+ } else if (line.toLowerCase().contains(CEC_PORT_BUSY.toLowerCase())) {
+ throw new CecClientWrapperException(ErrorCodes.CecPortBusy);
+ }
}
+ } catch (IOException ioe) {
+ throw new CecClientWrapperException(ErrorCodes.ReadConsole, ioe);
}
endTime = System.currentTimeMillis();
}
return false;
}
- /** Gets all the messages received from the given source device during a period of duration
+ /**
+ * Gets all the messages received from the given source device during a period of duration
* seconds.
*/
- public List<CecOperand> getAllMessages(LogicalAddress source, int duration) throws Exception {
+ public List<CecOperand> getAllMessages(LogicalAddress source, int duration)
+ throws CecClientWrapperException {
List<CecOperand> receivedOperands = new ArrayList<>();
long startTime = System.currentTimeMillis();
long endTime = startTime;
@@ -376,14 +430,18 @@
Pattern.CASE_INSENSITIVE);
while ((endTime - startTime <= (duration * 1000))) {
- if (mInputConsole.ready()) {
- String line = mInputConsole.readLine();
- if (pattern.matcher(line).matches()) {
- CecOperand operand = CecMessage.getOperand(line);
- if (!receivedOperands.contains(operand)) {
- receivedOperands.add(operand);
+ try {
+ if (mInputConsole.ready()) {
+ String line = mInputConsole.readLine();
+ if (pattern.matcher(line).matches()) {
+ CecOperand operand = CecMessage.getOperand(line);
+ if (!receivedOperands.contains(operand)) {
+ receivedOperands.add(operand);
+ }
}
}
+ } catch (IOException ioe) {
+ throw new CecClientWrapperException(ErrorCodes.ReadConsole, ioe);
}
endTime = System.currentTimeMillis();
}
@@ -395,7 +453,7 @@
* during a period of duration seconds.
*/
public List<LogicalAddress> getAllDestLogicalAddresses(CecOperand expectedMessage, int duration)
- throws Exception {
+ throws CecClientWrapperException {
return getAllDestLogicalAddresses(expectedMessage, "", duration);
}
@@ -404,7 +462,8 @@
* params during a period of duration seconds.
*/
public List<LogicalAddress> getAllDestLogicalAddresses(
- CecOperand expectedMessage, String params, int duration) throws Exception {
+ CecOperand expectedMessage, String params, int duration)
+ throws CecClientWrapperException {
List<LogicalAddress> destinationAddresses = new ArrayList<>();
long startTime = System.currentTimeMillis();
long endTime = startTime;
@@ -414,14 +473,18 @@
Pattern.CASE_INSENSITIVE);
while ((endTime - startTime <= (duration * 1000))) {
- if (mInputConsole.ready()) {
- String line = mInputConsole.readLine();
- if (pattern.matcher(line).matches()) {
- LogicalAddress destination = CecMessage.getDestination(line);
- if (!destinationAddresses.contains(destination)) {
- destinationAddresses.add(destination);
+ try {
+ if (mInputConsole.ready()) {
+ String line = mInputConsole.readLine();
+ if (pattern.matcher(line).matches()) {
+ LogicalAddress destination = CecMessage.getDestination(line);
+ if (!destinationAddresses.contains(destination)) {
+ destinationAddresses.add(destination);
+ }
}
}
+ } catch (IOException ioe) {
+ throw new CecClientWrapperException(ErrorCodes.ReadConsole, ioe);
}
endTime = System.currentTimeMillis();
}
@@ -431,30 +494,32 @@
/**
* Looks for the CEC expectedMessage broadcast on the cec-client communication channel and
* returns the first line that contains that message within default timeout. If the CEC message
- * is not found within the timeout, an exception is thrown.
+ * is not found within the timeout, an CecClientWrapperException is thrown.
*/
- public String checkExpectedOutput(CecOperand expectedMessage) throws Exception {
+ public String checkExpectedOutput(CecOperand expectedMessage) throws CecClientWrapperException {
return checkExpectedOutput(
targetDevice, LogicalAddress.BROADCAST, expectedMessage, DEFAULT_TIMEOUT, false);
}
/**
- * Looks for the CEC expectedMessage sent to CEC device toDevice on the cec-client
- * communication channel and returns the first line that contains that message within
- * default timeout. If the CEC message is not found within the timeout, an exception is thrown.
+ * Looks for the CEC expectedMessage sent to CEC device toDevice on the cec-client communication
+ * channel and returns the first line that contains that message within default timeout. If the
+ * CEC message is not found within the timeout, an CecClientWrapperException is thrown.
*/
- public String checkExpectedOutput(LogicalAddress toDevice,
- CecOperand expectedMessage) throws Exception {
+ public String checkExpectedOutput(LogicalAddress toDevice, CecOperand expectedMessage)
+ throws CecClientWrapperException {
return checkExpectedOutput(targetDevice, toDevice, expectedMessage, DEFAULT_TIMEOUT, false);
}
/**
* Looks for the broadcasted CEC expectedMessage sent from cec-client device fromDevice on the
* cec-client communication channel and returns the first line that contains that message within
- * default timeout. If the CEC message is not found within the timeout, an exception is thrown.
+ * default timeout. If the CEC message is not found within the timeout, an
+ * CecClientWrapperException is thrown.
*/
public String checkExpectedMessageFromClient(
- LogicalAddress fromDevice, CecOperand expectedMessage) throws Exception {
+ LogicalAddress fromDevice, CecOperand expectedMessage)
+ throws CecClientWrapperException {
return checkExpectedMessageFromClient(
fromDevice, LogicalAddress.BROADCAST, expectedMessage);
}
@@ -463,41 +528,42 @@
* Looks for the CEC expectedMessage sent from cec-client device fromDevice to CEC device
* toDevice on the cec-client communication channel and returns the first line that contains
* that message within default timeout. If the CEC message is not found within the timeout, an
- * exception is thrown.
+ * CecClientWrapperException is thrown.
*/
public String checkExpectedMessageFromClient(
LogicalAddress fromDevice, LogicalAddress toDevice, CecOperand expectedMessage)
- throws Exception {
+ throws CecClientWrapperException {
return checkExpectedOutput(fromDevice, toDevice, expectedMessage, DEFAULT_TIMEOUT, true);
}
/**
* Looks for the CEC expectedMessage broadcast on the cec-client communication channel and
- * returns the first line that contains that message within timeoutMillis. If the CEC message
- * is not found within the timeout, an exception is thrown.
+ * returns the first line that contains that message within timeoutMillis. If the CEC message is
+ * not found within the timeout, an CecClientWrapperException is thrown.
*/
- public String checkExpectedOutput(CecOperand expectedMessage,
- long timeoutMillis) throws Exception {
+ public String checkExpectedOutput(CecOperand expectedMessage, long timeoutMillis)
+ throws CecClientWrapperException {
return checkExpectedOutput(
targetDevice, LogicalAddress.BROADCAST, expectedMessage, timeoutMillis, false);
}
/**
- * Looks for the CEC expectedMessage sent to CEC device toDevice on the cec-client
- * communication channel and returns the first line that contains that message within
- * timeoutMillis. If the CEC message is not found within the timeout, an exception is thrown.
+ * Looks for the CEC expectedMessage sent to CEC device toDevice on the cec-client communication
+ * channel and returns the first line that contains that message within timeoutMillis. If the
+ * CEC message is not found within the timeout, an CecClientWrapperException is thrown.
*/
- public String checkExpectedOutput(LogicalAddress toDevice, CecOperand expectedMessage,
- long timeoutMillis) throws Exception {
+ public String checkExpectedOutput(
+ LogicalAddress toDevice, CecOperand expectedMessage, long timeoutMillis)
+ throws CecClientWrapperException {
return checkExpectedOutput(targetDevice, toDevice, expectedMessage, timeoutMillis, false);
}
/**
* Looks for the CEC expectedMessage sent from CEC device fromDevice to CEC device toDevice on
* the cec-client communication channel and returns the first line that contains that message
- * within timeoutMillis. If the CEC message is not found within the timeout, an exception is
- * thrown. This method looks for the CEC messages coming from Cec-client if fromCecClient is
- * true.
+ * within timeoutMillis. If the CEC message is not found within the timeout, an
+ * CecClientWrapperException is thrown. This method looks for the CEC messages coming from
+ * Cec-client if fromCecClient is true.
*/
public String checkExpectedOutput(
LogicalAddress fromDevice,
@@ -505,7 +571,7 @@
CecOperand expectedMessage,
long timeoutMillis,
boolean fromCecClient)
- throws Exception {
+ throws CecClientWrapperException {
checkCecClient();
long startTime = System.currentTimeMillis();
long endTime = startTime;
@@ -525,61 +591,66 @@
Pattern.CASE_INSENSITIVE);
while ((endTime - startTime <= timeoutMillis)) {
- if (mInputConsole.ready()) {
- String line = mInputConsole.readLine();
- if (pattern.matcher(line).matches()) {
- CLog.v("Found " + expectedMessage.name() + " in " + line);
- return line;
+ try {
+ if (mInputConsole.ready()) {
+ String line = mInputConsole.readLine();
+ if (pattern.matcher(line).matches()) {
+ CLog.v("Found " + expectedMessage.name() + " in " + line);
+ return line;
+ }
}
+ } catch (IOException ioe) {
+ throw new CecClientWrapperException(ErrorCodes.ReadConsole, ioe);
}
endTime = System.currentTimeMillis();
}
- throw new Exception("Could not find message " + expectedMessage.name());
+ throw new CecClientWrapperException(ErrorCodes.CecMessageNotFound, expectedMessage.name());
}
/**
* Looks for the CEC message incorrectMessage sent to CEC device toDevice on the cec-client
- * communication channel and throws an exception if it finds the line that contains the message
- * within the default timeout. If the CEC message is not found within the timeout, function
- * returns without error.
+ * communication channel and throws an CecClientWrapperException if it finds the line that
+ * contains the message within the default timeout. If the CEC message is not found within the
+ * timeout, function returns without error.
*/
- public void checkOutputDoesNotContainMessage(LogicalAddress toDevice,
- CecOperand incorrectMessage) throws Exception {
+ public void checkOutputDoesNotContainMessage(
+ LogicalAddress toDevice, CecOperand incorrectMessage) throws CecClientWrapperException {
checkOutputDoesNotContainMessage(toDevice, incorrectMessage, "", DEFAULT_TIMEOUT);
}
/**
* Looks for the CEC message incorrectMessage along with the params sent to CEC device toDevice
- * on the cec-client communication channel and throws an exception if it finds the line that
- * contains the message with its params within the default timeout. If the CEC message is not
- * found within the timeout, function returns without error.
+ * on the cec-client communication channel and throws an CecClientWrapperException if it finds
+ * the line that contains the message with its params within the default timeout. If the CEC
+ * message is not found within the timeout, function returns without error.
*/
public void checkOutputDoesNotContainMessage(
- LogicalAddress toDevice, CecOperand incorrectMessage, String params) throws Exception {
+ LogicalAddress toDevice, CecOperand incorrectMessage, String params)
+ throws CecClientWrapperException {
checkOutputDoesNotContainMessage(toDevice, incorrectMessage, params, DEFAULT_TIMEOUT);
}
/**
* Looks for the CEC message incorrectMessage sent to CEC device toDevice on the cec-client
- * communication channel and throws an exception if it finds the line that contains the message
- * within timeoutMillis. If the CEC message is not found within the timeout, function returns
- * without error.
+ * communication channel and throws an CecClientWrapperException if it finds the line that
+ * contains the message within timeoutMillis. If the CEC message is not found within the
+ * timeout, function returns without error.
*/
public void checkOutputDoesNotContainMessage(
LogicalAddress toDevice, CecOperand incorrectMessage, long timeoutMillis)
- throws Exception {
+ throws CecClientWrapperException {
checkOutputDoesNotContainMessage(toDevice, incorrectMessage, "", timeoutMillis);
}
/**
* Looks for the CEC message incorrectMessage along with the params sent to CEC device toDevice
- * on the cec-client communication channel and throws an exception if it finds the line that
- * contains the message and params within timeoutMillis. If the CEC message is not found within
- * the timeout, function returns without error.
+ * on the cec-client communication channel and throws an CecClientWrapperException if it finds
+ * the line that contains the message and params within timeoutMillis. If the CEC message is not
+ * found within the timeout, function returns without error.
*/
public void checkOutputDoesNotContainMessage(
LogicalAddress toDevice, CecOperand incorrectMessage, String params, long timeoutMillis)
- throws Exception {
+ throws CecClientWrapperException {
checkCecClient();
long startTime = System.currentTimeMillis();
long endTime = startTime;
@@ -597,13 +668,22 @@
Pattern.CASE_INSENSITIVE);
while ((endTime - startTime <= timeoutMillis)) {
- if (mInputConsole.ready()) {
- String line = mInputConsole.readLine();
- if (pattern.matcher(line).matches()) {
- CLog.v("Found " + incorrectMessage.name() + " in " + line);
- throw new Exception("Found " + incorrectMessage.name() + " to " + toDevice +
- " with params " + CecMessage.getParamsAsString(line));
+ try {
+ if (mInputConsole.ready()) {
+ String line = mInputConsole.readLine();
+ if (pattern.matcher(line).matches()) {
+ CLog.v("Found " + incorrectMessage.name() + " in " + line);
+ throw new CecClientWrapperException(
+ ErrorCodes.CecMessageFound,
+ incorrectMessage.name()
+ + " to "
+ + toDevice
+ + " with params "
+ + CecMessage.getParamsAsString(line));
+ }
}
+ } catch (IOException ioe) {
+ throw new CecClientWrapperException(ErrorCodes.ReadConsole, ioe);
}
endTime = System.currentTimeMillis();
}
@@ -615,7 +695,7 @@
}
/** Set the physical address of the cec-client instance */
- public void setPhysicalAddress(int newPhysicalAddress) throws Exception {
+ public void setPhysicalAddress(int newPhysicalAddress) throws CecClientWrapperException {
String command =
String.format(
"pa %02d %02d",
@@ -650,11 +730,11 @@
killProcess = RunUtil.getDefault().runCmdInBackground(commands);
killProcess.waitFor();
}
- } catch (Exception e) {
- /* If cec-client is not running, do not throw an exception, just return. */
- CLog.w(new Exception("Unable to close cec-client", e));
+ } catch (IOException | InterruptedException | CecClientWrapperException e) {
+ /*
+ * If cec-client is not running, do not throw a CecClientWrapperException, just return.
+ */
+ CLog.w(new CecClientWrapperException(ErrorCodes.CecClientStop, e));
}
}
-
- public class CecPortBusyException extends Exception {}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
index a97b478..2a5b4b7 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
@@ -49,6 +49,7 @@
public static final int CEC_DEVICE_TYPE_TUNER = 3;
public static final int CEC_DEVICE_TYPE_PLAYBACK_DEVICE = 4;
public static final int CEC_DEVICE_TYPE_AUDIO_SYSTEM = 5;
+ public static final int CEC_DEVICE_TYPE_SWITCH = 6;
/** Feature Abort Reasons */
public static final int ABORT_UNRECOGNIZED_MODE = 0;
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecAudioReturnChannelControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecAudioReturnChannelControlTest.java
index a8e43d3..7814e78 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecAudioReturnChannelControlTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecAudioReturnChannelControlTest.java
@@ -16,16 +16,14 @@
package android.hdmicec.cts.audio;
-import static org.junit.Assume.assumeNoException;
import android.hdmicec.cts.BaseHdmiCecCtsTest;
import android.hdmicec.cts.CecMessage;
import android.hdmicec.cts.CecOperand;
-import android.hdmicec.cts.HdmiCecClientWrapper;
+import android.hdmicec.cts.error.CecClientWrapperException;
+import android.hdmicec.cts.error.ErrorCodes;
import android.hdmicec.cts.HdmiCecConstants;
import android.hdmicec.cts.LogicalAddress;
-import android.hdmicec.cts.RequiredPropertyRule;
-import android.hdmicec.cts.RequiredFeatureRule;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -54,13 +52,15 @@
.around(CecRules.requiresDeviceType(this, AUDIO_DEVICE))
.around(hdmiCecClient);
- private void checkArcIsInitiated(){
+ private void checkArcIsInitiated() throws CecClientWrapperException {
try {
hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE,
CecOperand.REQUEST_ARC_INITIATION);
hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.INITIATE_ARC);
- } catch(Exception e) {
- assumeNoException(e);
+ } catch (CecClientWrapperException e) {
+ if (e.getErrorCode() != ErrorCodes.CecMessageNotFound) {
+ throw e;
+ }
}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecInvalidMessagesTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecInvalidMessagesTest.java
index 2b43cec..e0bccf4 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecInvalidMessagesTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecInvalidMessagesTest.java
@@ -16,21 +16,14 @@
package android.hdmicec.cts.audio;
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assume.assumeNoException;
-import static org.junit.Assume.assumeTrue;
import android.hdmicec.cts.BaseHdmiCecCtsTest;
import android.hdmicec.cts.CecMessage;
import android.hdmicec.cts.CecOperand;
-import android.hdmicec.cts.HdmiCecClientWrapper;
-import android.hdmicec.cts.HdmiCecConstants;
-import android.hdmicec.cts.LogHelper;
+import android.hdmicec.cts.error.CecClientWrapperException;
+import android.hdmicec.cts.error.ErrorCodes;
import android.hdmicec.cts.LogicalAddress;
-import android.hdmicec.cts.RequiredPropertyRule;
-import android.hdmicec.cts.RequiredFeatureRule;
-import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.Ignore;
@@ -45,7 +38,6 @@
public final class HdmiCecInvalidMessagesTest extends BaseHdmiCecCtsTest {
private static final LogicalAddress AUDIO_DEVICE = LogicalAddress.AUDIO_SYSTEM;
- private static final String PROPERTY_LOCALE = "persist.sys.locale";
/** The package name of the APK. */
private static final String PACKAGE = "android.hdmicec.app";
@@ -72,32 +64,15 @@
.around(CecRules.requiresDeviceType(this, AUDIO_DEVICE))
.around(hdmiCecClient);
- private String getSystemLocale() throws Exception {
- ITestDevice device = getDevice();
- return device.executeShellCommand("getprop " + PROPERTY_LOCALE).trim();
- }
-
- private void setSystemLocale(String locale) throws Exception {
- ITestDevice device = getDevice();
- device.executeShellCommand("setprop " + PROPERTY_LOCALE + " " + locale);
- }
-
- private boolean isLanguageEditable() throws Exception {
- String val = getDevice().executeShellCommand("getprop ro.hdmi.set_menu_language");
- return val.trim().equals("true") ? true : false;
- }
-
- private static String extractLanguage(String locale) {
- return locale.split("[^a-zA-Z]")[0];
- }
-
- private void checkArcIsInitiated(){
+ private void checkArcIsInitiated() throws CecClientWrapperException {
try {
hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE,
CecOperand.REQUEST_ARC_INITIATION);
hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.INITIATE_ARC);
- } catch(Exception e) {
- assumeNoException(e);
+ } catch (CecClientWrapperException e) {
+ if (e.getErrorCode() != ErrorCodes.CecMessageNotFound) {
+ throw e;
+ }
}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecDeviceTypeTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecDeviceTypeTest.java
index 284605e..548170b 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecDeviceTypeTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecDeviceTypeTest.java
@@ -16,17 +16,21 @@
package android.hdmicec.cts.common;
-import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+import android.hdmicec.cts.BaseHdmiCecCtsTest.CecRules;
import android.hdmicec.cts.HdmiCecConstants;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
import java.util.ArrayList;
@@ -39,6 +43,9 @@
@OptionClass(alias="hdmi-cec-cts-test")
public final class HdmiCecDeviceTypeTest extends BaseHostJUnit4Test {
+ @Rule
+ public RuleChain ruleChain = RuleChain.outerRule(CecRules.requiresLeanback(this));
+
@Option(name = HdmiCecConstants.PHYSICAL_ADDRESS_NAME,
description = "HDMI CEC physical address of the DUT",
mandatory = false)
@@ -48,24 +55,60 @@
*/
public static int dutPhysicalAddress = HdmiCecConstants.DEFAULT_PHYSICAL_ADDRESS;
- private static List<String> validTypes = new ArrayList<>(
- Arrays.asList("", "0", "4", "4,5", "5,4"));
+ int deviceTvOnly = setBit(HdmiCecConstants.CEC_DEVICE_TYPE_TV);
+ int devicePlaybackOnly = setBit(HdmiCecConstants.CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
+ int deviceComboTvSwitch =
+ setBit(HdmiCecConstants.CEC_DEVICE_TYPE_TV)
+ | setBit(HdmiCecConstants.CEC_DEVICE_TYPE_SWITCH);
+ int deviceComboPlaybackAudioSystem =
+ setBit(HdmiCecConstants.CEC_DEVICE_TYPE_PLAYBACK_DEVICE)
+ | setBit(HdmiCecConstants.CEC_DEVICE_TYPE_AUDIO_SYSTEM);
+ int deviceComboPlaybackAudioSystemSwitch =
+ setBit(HdmiCecConstants.CEC_DEVICE_TYPE_PLAYBACK_DEVICE)
+ | setBit(HdmiCecConstants.CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+ | setBit(HdmiCecConstants.CEC_DEVICE_TYPE_SWITCH);
+
+ private final List<Integer> allowedDeviceCombos =
+ new ArrayList<>(
+ Arrays.asList(
+ deviceTvOnly,
+ devicePlaybackOnly,
+ deviceComboTvSwitch,
+ deviceComboPlaybackAudioSystem,
+ deviceComboPlaybackAudioSystemSwitch));
+
/**
* Tests that the device declares a valid HDMI CEC device type.
*/
@Test
public void checkHdmiCecDeviceType() throws Exception {
- ITestDevice device = getDevice();
- String logs = device.executeShellCommand("cmd package list features");
- Scanner in = new Scanner(logs);
- while (in.hasNextLine()) {
- String line = in.nextLine();
- if (line.equals("feature:android.software.leanback")) {
- // Remove "" as valid device type if android.software.leanback feature is supported
- validTypes.remove("");
+ int deviceTypes = getAllDeviceTypes(getDevice());
+
+ assertWithMessage("Incorrect device combination")
+ .that(deviceTypes)
+ .isIn(allowedDeviceCombos);
+ }
+
+ private int getAllDeviceTypes(ITestDevice device) {
+ int deviceTypes = 0;
+ String deviceType = "";
+ try {
+ deviceType = device.executeShellCommand("getprop ro.hdmi.device_type").trim();
+ } catch (DeviceNotAvailableException dnae) {
+ return 0;
+ }
+
+ String[] cecDevices = deviceType.split(",");
+ for (String cecDevice : cecDevices) {
+ if (!cecDevice.equals("")) {
+ deviceTypes |= setBit(Integer.parseInt(cecDevice));
}
}
- String deviceType = device.executeShellCommand("getprop ro.hdmi.device_type");
- assertThat(deviceType.trim()).isIn(validTypes);
+
+ return deviceTypes;
+ }
+
+ private int setBit(int value) {
+ return (1 << value);
}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecInvalidMessagesTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecInvalidMessagesTest.java
index b36bcac..8ef4f22 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecInvalidMessagesTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecInvalidMessagesTest.java
@@ -39,8 +39,6 @@
@RunWith(DeviceJUnit4ClassRunner.class)
public final class HdmiCecInvalidMessagesTest extends BaseHdmiCecCtsTest {
- private static final String PROPERTY_LOCALE = "persist.sys.locale";
-
/** The package name of the APK. */
private static final String PACKAGE = "android.hdmicec.app";
@@ -64,25 +62,6 @@
.around(CecRules.requiresLeanback(this))
.around(hdmiCecClient);
- private String getSystemLocale() throws Exception {
- ITestDevice device = getDevice();
- return device.executeShellCommand("getprop " + PROPERTY_LOCALE).trim();
- }
-
- private void setSystemLocale(String locale) throws Exception {
- ITestDevice device = getDevice();
- device.executeShellCommand("setprop " + PROPERTY_LOCALE + " " + locale);
- }
-
- private boolean isLanguageEditable() throws Exception {
- String val = getDevice().executeShellCommand("getprop ro.hdmi.set_menu_language");
- return val.trim().equals("true") ? true : false;
- }
-
- private static String extractLanguage(String locale) {
- return locale.split("[^a-zA-Z]")[0];
- }
-
@Before
public void setup() {
source =
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/error/CecClientWrapperException.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/error/CecClientWrapperException.java
new file mode 100644
index 0000000..b8a6d63
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/error/CecClientWrapperException.java
@@ -0,0 +1,51 @@
+/*
+ * 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.hdmicec.cts.error;
+
+/**
+ * CecClientWrapperException to be thrown when there are any issues related with the usage of {@link
+ * HdmiCecClientWrapper}.
+ */
+public class CecClientWrapperException extends Exception {
+
+ private ErrorCodes errorCode;
+
+ public CecClientWrapperException(ErrorCodes errorCode) {
+ super(errorCode.getExceptionMessage());
+ this.errorCode = errorCode;
+ }
+
+ public CecClientWrapperException(ErrorCodes errorCode, String messageToBeAppend) {
+ super(errorCode.getExceptionMessage() + messageToBeAppend);
+ this.errorCode = errorCode;
+ }
+
+ public CecClientWrapperException(
+ ErrorCodes errorCode, Throwable cause, String messageToBeAppend) {
+ super(errorCode.getExceptionMessage() + messageToBeAppend, cause);
+ this.errorCode = errorCode;
+ }
+
+ public CecClientWrapperException(ErrorCodes errorCode, Throwable cause) {
+ super(errorCode.getExceptionMessage(), cause);
+ this.errorCode = errorCode;
+ }
+
+ public ErrorCodes getErrorCode() {
+ return this.errorCode;
+ }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/error/DumpsysParseException.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/error/DumpsysParseException.java
new file mode 100644
index 0000000..7645ff3
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/error/DumpsysParseException.java
@@ -0,0 +1,29 @@
+/*
+ * 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.hdmicec.cts.error;
+
+/** DumpsysParseException to be thrown when there are any issues while parsing the dumpsys. */
+public class DumpsysParseException extends Exception {
+
+ public DumpsysParseException(String message) {
+ super(message);
+ }
+
+ public DumpsysParseException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/error/ErrorCodes.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/error/ErrorCodes.java
new file mode 100644
index 0000000..4ade5b7
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/error/ErrorCodes.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hdmicec.cts.error;
+
+/** Enum contains the list of possible causes for an {@link CecClientWrapperException}. */
+public enum ErrorCodes {
+ CecMessageNotFound("Could not find CEC message "),
+ CecMessageFound("Found the CEC message "),
+ CecClientStart("Could not start the cec-client process "),
+ CecClientStop("Could not stop the cec-client process "),
+ CecClientNotRunning("Cec-client not running"),
+ CecPortBusy("Cec port busy "),
+ DeviceNotAvailable("Device not found "),
+ ReadConsole("Exception while reading from the console"),
+ WriteConsole("Exception while writing into the console");
+
+ private final String message;
+
+ public String getExceptionMessage() {
+ return this.message;
+ }
+
+ private ErrorCodes(String message) {
+ this.message = message;
+ }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemInformationTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemInformationTest.java
index 893a58e..58e5bf6 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemInformationTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemInformationTest.java
@@ -39,8 +39,6 @@
@RunWith(DeviceJUnit4ClassRunner.class)
public final class HdmiCecSystemInformationTest extends BaseHdmiCecCtsTest {
- private static final String PROPERTY_LOCALE = "persist.sys.locale";
-
@Rule
public RuleChain ruleChain =
RuleChain
@@ -66,25 +64,6 @@
assertThat(CecOperand.getOperand(abortedOpcode)).isEqualTo(CecOperand.GET_MENU_LANGUAGE);
}
- private String getSystemLocale() throws Exception {
- ITestDevice device = getDevice();
- return device.executeShellCommand("getprop " + PROPERTY_LOCALE).trim();
- }
-
- private void setSystemLocale(String locale) throws Exception {
- ITestDevice device = getDevice();
- device.executeShellCommand("setprop " + PROPERTY_LOCALE + " " + locale);
- }
-
- private boolean isLanguageEditable() throws Exception {
- String val = getDevice().executeShellCommand("getprop ro.hdmi.set_menu_language");
- return val.trim().equals("true") ? true : false;
- }
-
- private static String extractLanguage(String locale) {
- return locale.split("[^a-zA-Z]")[0];
- }
-
/**
* Test 11.2.6-3
* Tests that the device handles a <SET_MENU_LANGUAGE> with a valid language correctly.
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/targetprep/CecPortDiscoverer.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/targetprep/CecPortDiscoverer.java
index d9a3a25..5d49cb9 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/targetprep/CecPortDiscoverer.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/targetprep/CecPortDiscoverer.java
@@ -20,6 +20,8 @@
import android.hdmicec.cts.CecMessage;
import android.hdmicec.cts.HdmiCecClientWrapper;
import android.hdmicec.cts.HdmiCecConstants;
+import android.hdmicec.cts.error.CecClientWrapperException;
+import android.hdmicec.cts.error.ErrorCodes;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
@@ -42,7 +44,7 @@
/* Sets up the CEC tests by discovering which port the CEC adapter connected to */
public class CecPortDiscoverer extends BaseTargetPreparer {
- private static final int TIMEOUT_MILLIS = 10000;
+ private static final int TIMEOUT_MILLIS = 15000;
private static final int MAX_RETRY_COUNT = 3;
private File mCecMapDir = HdmiCecConstants.CEC_MAP_FOLDER;
@@ -87,6 +89,7 @@
HdmiCecClientWrapper cecClientWrapper = new HdmiCecClientWrapper();
launchCommand.add("cec-client");
+ String serialNo = "";
try {
List<String> comPorts = cecClientWrapper.getValidCecClientPorts();
@@ -106,7 +109,7 @@
launchCommand.add("x");
}
- String serialNo = device.getProperty("ro.serialno");
+ serialNo = device.getProperty("ro.serialno");
String serialNoParam = CecMessage.convertStringToHexParams(serialNo);
/*
* formatParams prefixes with a ':' that we do not want in the vendorcommand
@@ -131,6 +134,7 @@
*/
if (adapterMapping.exists()) {
/* Exit the current port's retry loop */
+ launchCommand.remove(port);
break;
}
mCecClient = RunUtil.getDefault().runCmdInBackground(launchCommand);
@@ -148,11 +152,18 @@
writeMapping(port, serialNo);
return;
}
+ /* Since it did not find the required message. Check another port */
+ portBeingRetried = false;
} else {
CLog.e("Console did not get ready!");
+ throw new CecClientWrapperException(ErrorCodes.CecPortBusy);
}
- } catch (HdmiCecClientWrapper.CecPortBusyException cpbe) {
- retryCount++;
+ } catch (CecClientWrapperException cwe) {
+ if (cwe.getErrorCode() != ErrorCodes.CecPortBusy) {
+ retryCount = MAX_RETRY_COUNT;
+ } else {
+ retryCount++;
+ }
if (retryCount >= MAX_RETRY_COUNT) {
/* We have retried enough number of times. Check another port */
portBeingRetried = false;
@@ -163,25 +174,31 @@
} finally {
/* Kill the unwanted cec-client process. */
Process killProcess = mCecClient.destroyForcibly();
- killProcess.waitFor();
- launchCommand.remove(port);
+ killProcess.waitFor(60, TimeUnit.SECONDS);
}
} while (portBeingRetried);
+ launchCommand.remove(port);
}
} catch (IOException | InterruptedException e) {
throw new TargetSetupError(
"Caught "
+ e.getClass().getSimpleName()
+ ". "
- + "Could not get adapter mapping.");
+ + "Could not get adapter mapping for device"
+ + serialNo
+ + ".",
+ e);
} catch (Exception generic) {
throw new TargetSetupError(
"Caught an exception with message '"
+ generic.getMessage()
+ "'. "
- + "Could not get adapter mapping.");
+ + "Could not get adapter mapping for device"
+ + serialNo
+ + ".",
+ generic);
}
- throw new TargetSetupError("Device not connected to any adapter!");
+ throw new TargetSetupError("Device " + serialNo + " not connected to any adapter!");
}
private String getPortFilename(String port) {
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecAudioReturnChannelControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecAudioReturnChannelControlTest.java
new file mode 100644
index 0000000..017c7c3
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecAudioReturnChannelControlTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hdmicec.cts.tv;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.hdmicec.cts.BaseHdmiCecCtsTest;
+import android.hdmicec.cts.CecMessage;
+import android.hdmicec.cts.CecOperand;
+import android.hdmicec.cts.HdmiCecConstants;
+import android.hdmicec.cts.LogicalAddress;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.runner.RunWith;
+
+/** HDMI CEC test to test audio return channel control (Section 11.2.17) */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class HdmiCecAudioReturnChannelControlTest extends BaseHdmiCecCtsTest {
+
+ private static final LogicalAddress TV_DEVICE = LogicalAddress.TV;
+
+ public HdmiCecAudioReturnChannelControlTest() {
+ super(TV_DEVICE, "-t", "a");
+ }
+
+ @Rule
+ public RuleChain ruleChain =
+ RuleChain.outerRule(CecRules.requiresCec(this))
+ .around(CecRules.requiresLeanback(this))
+ .around(CecRules.requiresDeviceType(this, TV_DEVICE))
+ .around(hdmiCecClient);
+
+ /**
+ * Test 11.1.17-1
+ *
+ * <p>Tests that the DUT sends a directly addressed {@code <Request ARC Initiation>} message.
+ */
+ @Ignore("b/187168483")
+ @Test
+ public void cect_11_1_17_1_DutSendsRequestArcInitiation() throws Exception {
+ // Ensure that ARC is off.
+ changeArcState(false);
+ hdmiCecClient.broadcastReportPhysicalAddress(LogicalAddress.AUDIO_SYSTEM);
+ assertWithMessage("DUT does not send a <Request ARC Initiation> message.")
+ .that(changeArcState(true))
+ .isTrue();
+ }
+
+ /**
+ * Test 11.1.17-2
+ *
+ * <p>Tests that the DUT responds with a directly addressed {@code <Report ARC initiated>}
+ * message to the Audio System when ARC is initiated.
+ */
+ @Ignore("b/174813656")
+ @Test
+ public void cect_11_1_17_2_ReportArcInitiated() throws Exception {
+ String params =
+ String.format(
+ "%04d%02d",
+ hdmiCecClient.getPhysicalAddress(),
+ HdmiCecConstants.CEC_DEVICE_TYPE_AUDIO_SYSTEM);
+ hdmiCecClient.sendCecMessage(
+ LogicalAddress.AUDIO_SYSTEM,
+ LogicalAddress.BROADCAST,
+ CecOperand.REPORT_PHYSICAL_ADDRESS,
+ CecMessage.formatParams(params));
+ hdmiCecClient.sendCecMessage(
+ LogicalAddress.AUDIO_SYSTEM, LogicalAddress.TV, CecOperand.INITIATE_ARC);
+ hdmiCecClient.checkExpectedOutput(LogicalAddress.AUDIO_SYSTEM, CecOperand.ARC_INITIATED);
+ }
+
+ /**
+ * Test 11.1.17-3
+ *
+ * <p>Tests that the DUT sends a directly addressed {@code <Request ARC Termination>} message.
+ */
+ @Ignore("b/187168483")
+ @Test
+ public void cect_11_1_17_3_DutSendsRequestArcTermination() throws Exception {
+ // Ensure that ARC is on.
+ changeArcState(true);
+ hdmiCecClient.broadcastReportPhysicalAddress(LogicalAddress.AUDIO_SYSTEM);
+ assertWithMessage("DUT does not send a <Request ARC Termination> message.")
+ .that(changeArcState(false))
+ .isTrue();
+ }
+
+ /**
+ * Test 11.1.17-2,4
+ *
+ * <p>Tests that the DUT responds with a directly addressed {@code <Report ARC terminated>}
+ * message to the Audio System when ARC is terminated.
+ */
+ @Ignore("b/174813656")
+ @Test
+ public void cect_11_1_17_2_4_ReportArcInitiatedTerminated() throws Exception {
+ /* We need to initiate ARC, so call the Initiate ARC test first */
+ cect_11_1_17_2_ReportArcInitiated();
+ hdmiCecClient.sendCecMessage(
+ LogicalAddress.AUDIO_SYSTEM, LogicalAddress.TV, CecOperand.TERMINATE_ARC);
+ hdmiCecClient.checkExpectedOutput(LogicalAddress.AUDIO_SYSTEM, CecOperand.ARC_TERMINATED);
+ }
+
+ /**
+ * Test 11.1.17-5
+ *
+ * <p>Tests that the DUT does not respond with any directly addressed {@code <Report ARC
+ * initiated>} message to a non-adjacent device
+ */
+ @Test
+ public void cect_11_1_17_5_NonAdjacentDeviceArcInitiation() throws Exception {
+ int originalPhyAdd = hdmiCecClient.getPhysicalAddress();
+ try {
+ int nonAdjacentPhyAdd = 0x1100;
+ String params =
+ CecMessage.formatParams(nonAdjacentPhyAdd)
+ + CecMessage.formatParams(
+ HdmiCecConstants.CEC_DEVICE_TYPE_AUDIO_SYSTEM);
+ /* Take physical address 1.1.0.0 */
+ hdmiCecClient.setPhysicalAddress(nonAdjacentPhyAdd);
+ hdmiCecClient.sendCecMessage(
+ LogicalAddress.AUDIO_SYSTEM,
+ LogicalAddress.BROADCAST,
+ CecOperand.REPORT_PHYSICAL_ADDRESS,
+ params);
+ hdmiCecClient.sendCecMessage(
+ LogicalAddress.AUDIO_SYSTEM, LogicalAddress.TV, CecOperand.INITIATE_ARC);
+ hdmiCecClient.checkOutputDoesNotContainMessage(
+ LogicalAddress.AUDIO_SYSTEM, CecOperand.ARC_INITIATED);
+ } finally {
+ /* Restore physical address */
+ hdmiCecClient.setPhysicalAddress(originalPhyAdd);
+ }
+ }
+
+ /**
+ * This method will turn on/off the ARC and ensure that it is processed successfully.
+ *
+ * @param enabled boolean value. Value true to turn ARC on.
+ * @return {@code true} if ARC process was successful.
+ */
+ private boolean changeArcState(boolean enabled) throws Exception {
+ getDevice().executeShellCommand("cmd hdmi_control setarc " + (enabled ? "on" : "off"));
+ try {
+ hdmiCecClient.checkExpectedOutput(
+ LogicalAddress.AUDIO_SYSTEM,
+ enabled
+ ? CecOperand.REQUEST_ARC_INITIATION
+ : CecOperand.REQUEST_ARC_TERMINATION);
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRemoteControlPassThroughTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRemoteControlPassThroughTest.java
index ad4dc5f..647f904 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRemoteControlPassThroughTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRemoteControlPassThroughTest.java
@@ -22,6 +22,8 @@
import android.hdmicec.cts.BaseHdmiCecCtsTest;
import android.hdmicec.cts.CecMessage;
import android.hdmicec.cts.CecOperand;
+import android.hdmicec.cts.error.CecClientWrapperException;
+import android.hdmicec.cts.error.ErrorCodes;
import android.hdmicec.cts.HdmiCecConstants;
import android.hdmicec.cts.LogicalAddress;
@@ -58,7 +60,7 @@
}
@Before
- public void checkForInitialActiveSourceMessage() throws Exception {
+ public void checkForInitialActiveSourceMessage() throws CecClientWrapperException {
try {
/*
* Check for the broadcasted <ACTIVE_SOURCE> message from Recorder_1, which was sent as
@@ -67,14 +69,18 @@
String message =
hdmiCecClient.checkExpectedMessageFromClient(
LogicalAddress.RECORDER_1, CecOperand.ACTIVE_SOURCE);
- } catch (Exception e) {
- /*
- * In case the TV does not send <Set Stream Path> to CEC adapter, or the client does
- * not make recorder active source, broadcast an <Active Source> message from the
- * adapter.
- */
- hdmiCecClient.broadcastActiveSource(
- LogicalAddress.RECORDER_1, hdmiCecClient.getPhysicalAddress());
+ } catch (CecClientWrapperException e) {
+ if (e.getErrorCode() != ErrorCodes.CecMessageNotFound) {
+ throw e;
+ } else {
+ /*
+ * In case the TV does not send <Set Stream Path> to CEC adapter, or the client does
+ * not make recorder active source, broadcast an <Active Source> message from the
+ * adapter.
+ */
+ hdmiCecClient.broadcastActiveSource(
+ LogicalAddress.RECORDER_1, hdmiCecClient.getPhysicalAddress());
+ }
}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRoutingControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRoutingControlTest.java
index a3c803d..665c7b1 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRoutingControlTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRoutingControlTest.java
@@ -21,6 +21,8 @@
import android.hdmicec.cts.BaseHdmiCecCtsTest;
import android.hdmicec.cts.CecMessage;
import android.hdmicec.cts.CecOperand;
+import android.hdmicec.cts.error.CecClientWrapperException;
+import android.hdmicec.cts.error.ErrorCodes;
import android.hdmicec.cts.HdmiControlManagerUtility;
import android.hdmicec.cts.LogicalAddress;
@@ -50,7 +52,7 @@
}
@Before
- public void checkForInitialActiveSourceMessage() throws Exception {
+ public void checkForInitialActiveSourceMessage() throws CecClientWrapperException {
try {
/*
* Check for the broadcasted <ACTIVE_SOURCE> message from Recorder_1, which was sent as
@@ -59,14 +61,18 @@
String message =
hdmiCecClient.checkExpectedMessageFromClient(
LogicalAddress.RECORDER_1, CecOperand.ACTIVE_SOURCE);
- } catch (Exception e) {
- /*
- * In case the TV does not send <Set Stream Path> to CEC adapter, or the client does
- * not make recorder active source, broadcast an <Active Source> message from the
- * adapter.
- */
- hdmiCecClient.broadcastActiveSource(
- hdmiCecClient.getSelfDevice(), hdmiCecClient.getPhysicalAddress());
+ } catch (CecClientWrapperException e) {
+ if (e.getErrorCode() != ErrorCodes.CecMessageNotFound) {
+ throw e;
+ } else {
+ /*
+ * In case the TV does not send <Set Stream Path> to CEC adapter, or the client does
+ * not make recorder active source, broadcast an <Active Source> message from the
+ * adapter.
+ */
+ hdmiCecClient.broadcastActiveSource(
+ hdmiCecClient.getSelfDevice(), hdmiCecClient.getPhysicalAddress());
+ }
}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecSystemAudioControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecSystemAudioControlTest.java
index 4a4bf92..ca5a050 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecSystemAudioControlTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecSystemAudioControlTest.java
@@ -47,7 +47,50 @@
.around(hdmiCecClient);
public HdmiCecSystemAudioControlTest() {
- super(LogicalAddress.TV, "-t", "a");
+ super(LogicalAddress.TV, "-t", "a", "-t", "r");
+ }
+
+ /**
+ * Test 11.1.15-1
+ *
+ * <p>Tests that the DUT sends a correctly formatted {@code <System Audio Mode Request>}
+ * message.
+ */
+ @Test
+ public void cect_11_1_15_1_DutSendsSystemAudioModeRequest() throws Exception {
+ hdmiCecClient.broadcastReportPhysicalAddress(LogicalAddress.AUDIO_SYSTEM);
+ hdmiCecClient.broadcastReportPhysicalAddress(
+ LogicalAddress.RECORDER_1, hdmiCecClient.getPhysicalAddress());
+ hdmiCecClient.sendCecMessage(LogicalAddress.RECORDER_1, CecOperand.IMAGE_VIEW_ON);
+ hdmiCecClient.broadcastActiveSource(
+ LogicalAddress.RECORDER_1, hdmiCecClient.getPhysicalAddress());
+ /*
+ * Invoke the DUT to turn on the system audio mode and check for system audio mode request
+ * message with params.
+ */
+ assertWithMessage("Device did not send a <System Audio Mode Request> message with params")
+ .that(setSystemAudioMode(true))
+ .isTrue();
+ }
+
+ /**
+ * Test 11.1.15-5
+ *
+ * <p>Tests that the DUT sends a correctly formatted {@code <System Audio Mode Request>} message
+ * when the DUT invokes the System Audio Mode to be Off.
+ */
+ @Test
+ public void cect_11_1_15_5_DutResponseWhenSystemAudioModeToOff() throws Exception {
+ // Ensure that system audio mode is on.
+ setSystemAudioMode(true);
+ /*
+ * Invoke the DUT to turn off the system audio mode and check for system audio mode request
+ * message with no params.
+ */
+ assertWithMessage(
+ "Device did not send a <System Audio Mode Request> message with no params")
+ .that(setSystemAudioMode(false))
+ .isTrue();
}
/**
@@ -105,4 +148,21 @@
.that(AudioManagerHelper.isDeviceMuted(getDevice()))
.isFalse();
}
+
+ private boolean setSystemAudioMode(boolean enabled) throws Exception {
+ getDevice().executeShellCommand("cmd hdmi_control setsam " + (enabled ? "on" : "off"));
+ try {
+ String message =
+ hdmiCecClient.checkExpectedOutput(
+ LogicalAddress.AUDIO_SYSTEM, CecOperand.SYSTEM_AUDIO_MODE_REQUEST);
+ /*
+ * When system audio mode is turned off. DUT should send <System Audio Mode Request>
+ * message with no params. And when it is turned on, DUT should send the same message
+ * with params.
+ */
+ return enabled ^ CecMessage.getParamsAsString(message).equals("");
+ } catch (Exception e) {
+ return false;
+ }
+ }
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecSystemInformationTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecSystemInformationTest.java
new file mode 100644
index 0000000..777c5ca
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecSystemInformationTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hdmicec.cts.tv;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.hdmicec.cts.BaseHdmiCecCtsTest;
+import android.hdmicec.cts.CecMessage;
+import android.hdmicec.cts.CecOperand;
+import android.hdmicec.cts.LogicalAddress;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+/** HDMI CEC system information tests (Section 11.1.6) */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class HdmiCecSystemInformationTest extends BaseHdmiCecCtsTest {
+
+ @Rule
+ public RuleChain ruleChain =
+ RuleChain.outerRule(CecRules.requiresCec(this))
+ .around(CecRules.requiresLeanback(this))
+ .around(CecRules.requiresDeviceType(this, LogicalAddress.TV))
+ .around(hdmiCecClient);
+
+ public HdmiCecSystemInformationTest() {
+ super(LogicalAddress.TV);
+ }
+
+ /**
+ * Test 11.1.6-5
+ *
+ * <p>Tests that the device responds correctly to a {@code <Get Menu Language>} message coming
+ * from various logical addresses (1, 3, 4, 5, 13, 14 and 15).
+ */
+ @Test
+ public void cect_11_1_6_5_DutRespondsToGetMenuLanguage() throws Exception {
+ final String tvLanguage = new Locale(extractLanguage(getSystemLocale())).getISO3Language();
+ String message;
+ LogicalAddress sources[] = {
+ LogicalAddress.RECORDER_1,
+ LogicalAddress.TUNER_1,
+ LogicalAddress.PLAYBACK_1,
+ LogicalAddress.AUDIO_SYSTEM,
+ LogicalAddress.RESERVED_2,
+ LogicalAddress.SPECIFIC_USE,
+ LogicalAddress.BROADCAST
+ };
+ for (LogicalAddress source : sources) {
+ hdmiCecClient.sendCecMessage(source, CecOperand.GET_MENU_LANGUAGE);
+ message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_MENU_LANGUAGE);
+ assertThat(CecMessage.getAsciiString(message)).isEqualTo(tvLanguage);
+ }
+ }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecTvOneTouchPlayTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecTvOneTouchPlayTest.java
index ee6fafa..fef8b62 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecTvOneTouchPlayTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecTvOneTouchPlayTest.java
@@ -18,6 +18,7 @@
import android.hdmicec.cts.BaseHdmiCecCtsTest;
import android.hdmicec.cts.CecOperand;
+import android.hdmicec.cts.HdmiControlManagerUtility;
import android.hdmicec.cts.LogicalAddress;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -94,4 +95,36 @@
.isEqualTo(testDevice);
}
}
+
+ /**
+ * Test 11.1.1-5
+ *
+ * <p>Tests that the DUT broadcasts an {@code <Active Source>} message when changing to an
+ * internal source from previously displaying an external source.
+ */
+ @Test
+ public void cect_11_1_1_5_DutBroadcastsActiveSourceWhenChangingToInternal() throws Exception {
+ // Ensure that an external source is the active source.
+ try {
+ /*
+ * Check for the broadcasted <ACTIVE_SOURCE> message from Recorder_1, which was sent as
+ * a response to <SET_STREAM_PATH> message from the TV.
+ */
+ String message =
+ hdmiCecClient.checkExpectedMessageFromClient(
+ LogicalAddress.RECORDER_1, CecOperand.ACTIVE_SOURCE);
+ } catch (Exception e) {
+ /*
+ * In case the TV does not send <Set Stream Path> to CEC adapter, or the client does
+ * not make recorder active source, broadcast an <Active Source> message from the
+ * adapter.
+ */
+ hdmiCecClient.broadcastActiveSource(
+ LogicalAddress.RECORDER_1, hdmiCecClient.getPhysicalAddress());
+ }
+ // Make the TV device the active source.
+ HdmiControlManagerUtility.setActiveSource(
+ getDevice(), LogicalAddress.TV.getLogicalAddressAsInt());
+ hdmiCecClient.checkExpectedOutput(LogicalAddress.BROADCAST, CecOperand.ACTIVE_SOURCE);
+ }
}
diff --git a/hostsidetests/incident/apps/batterystatsapp/Android.bp b/hostsidetests/incident/apps/batterystatsapp/Android.bp
index 96f6c37..cb3e3b7 100644
--- a/hostsidetests/incident/apps/batterystatsapp/Android.bp
+++ b/hostsidetests/incident/apps/batterystatsapp/Android.bp
@@ -29,6 +29,7 @@
"ctstestrunner-axt",
"compatibility-device-util-axt",
"androidx.legacy_legacy-support-v4",
+ "testng", // for org.test.* support
],
sdk_version: "test_current",
// tag this module as a cts test artifact
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsRadioPowerStateTest.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsRadioPowerStateTest.java
new file mode 100644
index 0000000..d384852
--- /dev/null
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsRadioPowerStateTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.cts.device.batterystats;
+
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+
+import static junit.framework.Assert.assertTrue;
+
+import static org.testng.Assert.assertThrows;
+
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
+import android.os.BatteryStatsManager;
+import android.os.SystemClock;
+import android.system.Os;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.regex.Pattern;
+
+@RunWith(AndroidJUnit4.class)
+public class BatteryStatsRadioPowerStateTest {
+ private static final int UID = Os.getuid();
+ private static final String PATTERN_MOBILE = "modem-data";
+ private static final String PATTERN_WIFI = "wifi-data";
+ private BatteryStatsManager mBsm;
+ private ConnectivityManager mCm;
+ private Instrumentation mInstrumentation;
+ private Context mContext;
+ private UiAutomation mUiAutomation;
+
+ @Before
+ public void setUp() throws Exception {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mContext = mInstrumentation.getContext();
+ mUiAutomation = mInstrumentation.getUiAutomation();
+ mBsm = mContext.getSystemService(BatteryStatsManager.class);
+ mCm = mContext.getSystemService(ConnectivityManager.class);
+ }
+
+ @Test
+ public void testReportMobileRadioPowerState() throws Exception {
+ // Expect fail w/o UPDATE_DEVICE_STATS permission.
+ assertThrows(SecurityException.class, () -> mBsm.reportMobileRadioPowerState(true, UID));
+
+ mUiAutomation.adoptShellPermissionIdentity();
+ final NetworkCapabilities activeNc = mCm.getNetworkCapabilities(mCm.getActiveNetwork());
+ final boolean expectedCurrentMobileRadio = (activeNc == null) ? false :
+ activeNc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
+ try {
+ // Skip other information before testing to reduce the information contained in the dump
+ // result.
+ final long time = SystemClock.elapsedRealtime();
+ final String cmd = "dumpsys batterystats --history-start " + time;
+ // Mobile radio power stats only updates when:
+ // 1. the radio state is changed, and
+ // 2. the radio power is inactive.
+ // Thus, trigger twice with different radio power state to ensure that it updates.
+ mBsm.reportMobileRadioPowerState(!expectedCurrentMobileRadio, UID);
+ mBsm.reportMobileRadioPowerState(expectedCurrentMobileRadio, UID);
+ final String dump = runShellCommand(mInstrumentation, cmd);
+ assertTrue(Pattern.compile(PATTERN_MOBILE).matcher(dump).find());
+ } finally {
+ // Restore state
+ mBsm.reportMobileRadioPowerState(expectedCurrentMobileRadio, UID);
+ mUiAutomation.dropShellPermissionIdentity();
+ }
+ }
+
+ @Test
+ public void testReportWifiRadioPowerState() throws Exception {
+ // Expect fail w/o UPDATE_DEVICE_STATS permission.
+ assertThrows(SecurityException.class, () -> mBsm.reportWifiRadioPowerState(true, UID));
+
+ mUiAutomation.adoptShellPermissionIdentity();
+ final NetworkCapabilities activeNc = mCm.getNetworkCapabilities(mCm.getActiveNetwork());
+ final boolean expectedCurrentWifiRadio = (activeNc == null) ? false :
+ activeNc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
+ try {
+ // Skip other information before testing to reduce the information contained in the dump
+ // result.
+ final long time = SystemClock.elapsedRealtime();
+ final String cmd = "dumpsys batterystats --history-start " + time;
+ mBsm.reportWifiRadioPowerState(!expectedCurrentWifiRadio, UID);
+ final String dump = runShellCommand(mInstrumentation, cmd);
+ assertTrue(Pattern.compile(PATTERN_WIFI).matcher(dump).find());
+ } finally {
+ // Restore state
+ mBsm.reportWifiRadioPowerState(expectedCurrentWifiRadio, UID);
+ mUiAutomation.dropShellPermissionIdentity();
+ }
+ }
+}
diff --git a/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java b/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
index ce6f04e..4123ad8 100644
--- a/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
@@ -254,6 +254,21 @@
batteryOffScreenOn();
}
+ public void testReportRadioPowerState() throws Exception {
+ // Simulate usb unplugged.
+ batteryOnScreenOff();
+
+ installPackage(DEVICE_SIDE_TEST_APK, true);
+ allowImmediateSyncs();
+
+ runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsRadioPowerStateTest",
+ "testReportMobileRadioPowerState");
+ runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsRadioPowerStateTest",
+ "testReportWifiRadioPowerState");
+
+ batteryOffScreenOn();
+ }
+
private int getUid() throws Exception {
String uidLine = getDevice().executeShellCommand("cmd package list packages -U "
+ DEVICE_SIDE_TEST_PACKAGE);
diff --git a/hostsidetests/incident/src/com/android/server/cts/JobSchedulerIncidentTest.java b/hostsidetests/incident/src/com/android/server/cts/JobSchedulerIncidentTest.java
index 3c807fa..27f2c76 100644
--- a/hostsidetests/incident/src/com/android/server/cts/JobSchedulerIncidentTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/JobSchedulerIncidentTest.java
@@ -19,6 +19,7 @@
import android.app.job.StopReasonEnum;
import android.net.NetworkCapabilitiesProto;
import android.net.NetworkRequestProto;
+import android.net.Transport;
import com.android.server.job.ConstantsProto;
import com.android.server.job.ConstraintEnum;
import com.android.server.job.DataSetProto;
@@ -228,8 +229,8 @@
private static void testNetworkCapabilitesProto(NetworkCapabilitiesProto nc) throws Exception {
assertNotNull(nc);
- for (NetworkCapabilitiesProto.Transport t : nc.getTransportsList()) {
- assertTrue(NetworkCapabilitiesProto.Transport.getDescriptor().getValues()
+ for (Transport t : nc.getTransportsList()) {
+ assertTrue(Transport.getDescriptor().getValues()
.contains(t.getValueDescriptor()));
}
for (NetworkCapabilitiesProto.NetCapability c : nc.getCapabilitiesList()) {
diff --git a/hostsidetests/incrementalinstall/OWNERS b/hostsidetests/incrementalinstall/OWNERS
index d16fb6c..49bed85 100644
--- a/hostsidetests/incrementalinstall/OWNERS
+++ b/hostsidetests/incrementalinstall/OWNERS
@@ -3,4 +3,5 @@
alexbuy@google.com
schfan@google.com
toddke@google.com
+patb@google.com
zyy@google.com
\ No newline at end of file
diff --git a/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/InputMethodServiceDeviceTest.java b/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/InputMethodServiceDeviceTest.java
index 2d95ca2..33f0986 100644
--- a/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/InputMethodServiceDeviceTest.java
+++ b/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/InputMethodServiceDeviceTest.java
@@ -71,6 +71,8 @@
@RunWith(AndroidJUnit4.class)
public class InputMethodServiceDeviceTest {
+ private static final String FEATURE_WATCH = "android.hardware.type.watch";
+
private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(20);
/** Test to check CtsInputMethod1 receives onCreate and onStartInput. */
@@ -324,6 +326,17 @@
InputMethodVisibilityVerifier.assertIme2Visible(TIMEOUT);
+ if (helper.shell("pm list features").contains(FEATURE_WATCH)) {
+ // Skip if running on Wear devices because those devices will go through an activity
+ // change during screen off/on cycle due to Ambient mode. Activity change will cause
+ // EditText to retain focus but not show IME.
+ // We also do not use "assumeFalse" because this test is executed as part of
+ // host-side tests, and throwing AssumptionViolatedException would not give us
+ // better understanding about what is happening.
+ // TODO(b/188662291): Remove this while introducing a dedicated test for b/b/160391516.
+ return;
+ }
+
// Make sure the IME switch UI still works after device screen off / on with focusing
// same Editor.
turnScreenOff(helper);
diff --git a/hostsidetests/jvmti/allocation-tracking/Android.bp b/hostsidetests/jvmti/allocation-tracking/Android.bp
index b74f19a60..07956a3 100644
--- a/hostsidetests/jvmti/allocation-tracking/Android.bp
+++ b/hostsidetests/jvmti/allocation-tracking/Android.bp
@@ -24,4 +24,7 @@
"cts",
"general-tests",
],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/attaching/Android.bp b/hostsidetests/jvmti/attaching/Android.bp
index 0147b329..3e6a692 100644
--- a/hostsidetests/jvmti/attaching/Android.bp
+++ b/hostsidetests/jvmti/attaching/Android.bp
@@ -89,4 +89,7 @@
],
test_config: "host/AndroidTest.xml",
data: [":CtsJvmtiAttachingDeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java b/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java
index 0fee0ec..cecb6ed 100644
--- a/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java
+++ b/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java
@@ -77,9 +77,17 @@
mAbi = arg0;
}
+ // Constant returned to indicate get-current-user failed. See comment at/near
+ // https://cs.android.com/android/_/android/platform/tools/tradefederation/+/android11-release:device_build_interfaces/com/android/tradefed/device/ITestDevice.java;l=780
+ private static final int GET_USER_FAILURE = -10000;
+
+ // Try getting current user and throw an exception immediately if we fail.
@Override
protected void setUp() throws Exception {
mCurrentUser = getDevice().getCurrentUser();
+ if (mCurrentUser == GET_USER_FAILURE) {
+ throw new RuntimeException("am get-current-user failed!");
+ }
}
public void testJvmti() throws Exception {
diff --git a/hostsidetests/jvmti/redefining/Android.bp b/hostsidetests/jvmti/redefining/Android.bp
index 4816fd8..b8c1f63 100644
--- a/hostsidetests/jvmti/redefining/Android.bp
+++ b/hostsidetests/jvmti/redefining/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRedefineClassesDeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1900/Android.bp b/hostsidetests/jvmti/run-tests/test-1900/Android.bp
index 4b6326f..741785b 100644
--- a/hostsidetests/jvmti/run-tests/test-1900/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1900/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1900DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1901/Android.bp b/hostsidetests/jvmti/run-tests/test-1901/Android.bp
index 928ae4f..88b2f5e 100644
--- a/hostsidetests/jvmti/run-tests/test-1901/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1901/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1901DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1902/Android.bp b/hostsidetests/jvmti/run-tests/test-1902/Android.bp
index a2a4e8d..7c9b6f1 100644
--- a/hostsidetests/jvmti/run-tests/test-1902/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1902/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1902DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1903/Android.bp b/hostsidetests/jvmti/run-tests/test-1903/Android.bp
index f583f8e..17f981f 100644
--- a/hostsidetests/jvmti/run-tests/test-1903/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1903/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1903DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1904/Android.bp b/hostsidetests/jvmti/run-tests/test-1904/Android.bp
index 71de778..a45f2f6 100644
--- a/hostsidetests/jvmti/run-tests/test-1904/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1904/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1904DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1906/Android.bp b/hostsidetests/jvmti/run-tests/test-1906/Android.bp
index 9665afd..b95c443 100644
--- a/hostsidetests/jvmti/run-tests/test-1906/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1906/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1906DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1907/Android.bp b/hostsidetests/jvmti/run-tests/test-1907/Android.bp
index 960f194..751e1ab 100644
--- a/hostsidetests/jvmti/run-tests/test-1907/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1907/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1907DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1908/Android.bp b/hostsidetests/jvmti/run-tests/test-1908/Android.bp
index 5d6dcbf..8d4ac4c 100644
--- a/hostsidetests/jvmti/run-tests/test-1908/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1908/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1908DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1909/Android.bp b/hostsidetests/jvmti/run-tests/test-1909/Android.bp
index 049ef1d..c12f5d4 100644
--- a/hostsidetests/jvmti/run-tests/test-1909/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1909/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1909DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1910/Android.bp b/hostsidetests/jvmti/run-tests/test-1910/Android.bp
index 9165c27..0fb1630 100644
--- a/hostsidetests/jvmti/run-tests/test-1910/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1910/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1910DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1911/Android.bp b/hostsidetests/jvmti/run-tests/test-1911/Android.bp
index 609793d..fe5cf2a 100644
--- a/hostsidetests/jvmti/run-tests/test-1911/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1911/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1911DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1912/Android.bp b/hostsidetests/jvmti/run-tests/test-1912/Android.bp
index 903e43d..23bf2ce 100644
--- a/hostsidetests/jvmti/run-tests/test-1912/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1912/Android.bp
@@ -24,5 +24,8 @@
"cts",
"general-tests",
],
- data: [":CtsJvmtiRunTest1912DeviceApp"]
-}
+ data: [":CtsJvmtiRunTest1912DeviceApp"],
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1913/Android.bp b/hostsidetests/jvmti/run-tests/test-1913/Android.bp
index 96c6368..0fe2d08 100644
--- a/hostsidetests/jvmti/run-tests/test-1913/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1913/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1913DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1914/Android.bp b/hostsidetests/jvmti/run-tests/test-1914/Android.bp
index f5ff8cc..7c0de98 100644
--- a/hostsidetests/jvmti/run-tests/test-1914/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1914/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1914DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1915/Android.bp b/hostsidetests/jvmti/run-tests/test-1915/Android.bp
index 49ee753..245fa3f 100644
--- a/hostsidetests/jvmti/run-tests/test-1915/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1915/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1915DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1916/Android.bp b/hostsidetests/jvmti/run-tests/test-1916/Android.bp
index f4e5c89..c4662a3 100644
--- a/hostsidetests/jvmti/run-tests/test-1916/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1916/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1916DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1917/Android.bp b/hostsidetests/jvmti/run-tests/test-1917/Android.bp
index cb82cdb..82bfdbf 100644
--- a/hostsidetests/jvmti/run-tests/test-1917/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1917/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1917DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1920/Android.bp b/hostsidetests/jvmti/run-tests/test-1920/Android.bp
index 1fac722e..f7f2a16 100644
--- a/hostsidetests/jvmti/run-tests/test-1920/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1920/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1920DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1921/Android.bp b/hostsidetests/jvmti/run-tests/test-1921/Android.bp
index 16ca73d..dbb927c 100644
--- a/hostsidetests/jvmti/run-tests/test-1921/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1921/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1921DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1922/Android.bp b/hostsidetests/jvmti/run-tests/test-1922/Android.bp
index 1cf47ec..def8205 100644
--- a/hostsidetests/jvmti/run-tests/test-1922/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1922/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1922DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1923/Android.bp b/hostsidetests/jvmti/run-tests/test-1923/Android.bp
index 3f20a27..d9a37c4 100644
--- a/hostsidetests/jvmti/run-tests/test-1923/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1923/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1923DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1924/Android.bp b/hostsidetests/jvmti/run-tests/test-1924/Android.bp
index 36fcd19..c370630 100644
--- a/hostsidetests/jvmti/run-tests/test-1924/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1924/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1924DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1925/Android.bp b/hostsidetests/jvmti/run-tests/test-1925/Android.bp
index b3d7d82..131b507 100644
--- a/hostsidetests/jvmti/run-tests/test-1925/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1925/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1925DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1926/Android.bp b/hostsidetests/jvmti/run-tests/test-1926/Android.bp
index 3420b61..c4ca4ea 100644
--- a/hostsidetests/jvmti/run-tests/test-1926/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1926/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1926DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1927/Android.bp b/hostsidetests/jvmti/run-tests/test-1927/Android.bp
index 88229ff..94297f7 100644
--- a/hostsidetests/jvmti/run-tests/test-1927/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1927/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1927DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1928/Android.bp b/hostsidetests/jvmti/run-tests/test-1928/Android.bp
index fe94bb8..8232670 100644
--- a/hostsidetests/jvmti/run-tests/test-1928/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1928/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1928DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1930/Android.bp b/hostsidetests/jvmti/run-tests/test-1930/Android.bp
index b80e3b0..104167d 100644
--- a/hostsidetests/jvmti/run-tests/test-1930/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1930/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1930DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1931/Android.bp b/hostsidetests/jvmti/run-tests/test-1931/Android.bp
index 972f75e..7fef39d 100644
--- a/hostsidetests/jvmti/run-tests/test-1931/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1931/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1931DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1932/Android.bp b/hostsidetests/jvmti/run-tests/test-1932/Android.bp
index ff0d225..0009ba5 100644
--- a/hostsidetests/jvmti/run-tests/test-1932/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1932/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1932DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1933/Android.bp b/hostsidetests/jvmti/run-tests/test-1933/Android.bp
index 1b0f483..b7285d6 100644
--- a/hostsidetests/jvmti/run-tests/test-1933/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1933/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1933DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1934/Android.bp b/hostsidetests/jvmti/run-tests/test-1934/Android.bp
index 079f6de..23055d8 100644
--- a/hostsidetests/jvmti/run-tests/test-1934/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1934/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1934DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1936/Android.bp b/hostsidetests/jvmti/run-tests/test-1936/Android.bp
index ff1c9a5..e2e4484 100644
--- a/hostsidetests/jvmti/run-tests/test-1936/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1936/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1936DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1937/Android.bp b/hostsidetests/jvmti/run-tests/test-1937/Android.bp
index 695edb2..b3eb90d 100644
--- a/hostsidetests/jvmti/run-tests/test-1937/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1937/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1937DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1939/Android.bp b/hostsidetests/jvmti/run-tests/test-1939/Android.bp
index b82555f3..f2b8f8e 100644
--- a/hostsidetests/jvmti/run-tests/test-1939/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1939/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1939DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1941/Android.bp b/hostsidetests/jvmti/run-tests/test-1941/Android.bp
index 7134464..21b4a62 100644
--- a/hostsidetests/jvmti/run-tests/test-1941/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1941/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1941DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1942/Android.bp b/hostsidetests/jvmti/run-tests/test-1942/Android.bp
index a5163e2..cbd2c73 100644
--- a/hostsidetests/jvmti/run-tests/test-1942/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1942/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1942DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1943/Android.bp b/hostsidetests/jvmti/run-tests/test-1943/Android.bp
index a7efc95..c185433 100644
--- a/hostsidetests/jvmti/run-tests/test-1943/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1943/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1943DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1953/Android.bp b/hostsidetests/jvmti/run-tests/test-1953/Android.bp
index d2251b2..67fc6ff 100644
--- a/hostsidetests/jvmti/run-tests/test-1953/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1953/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1953DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1958/Android.bp b/hostsidetests/jvmti/run-tests/test-1958/Android.bp
index 721bb03..eb80ec5 100644
--- a/hostsidetests/jvmti/run-tests/test-1958/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1958/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1958DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1962/Android.bp b/hostsidetests/jvmti/run-tests/test-1962/Android.bp
index 662cacc..04ead5f 100644
--- a/hostsidetests/jvmti/run-tests/test-1962/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1962/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1962DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1967/Android.bp b/hostsidetests/jvmti/run-tests/test-1967/Android.bp
index 995959e..6c9b570 100644
--- a/hostsidetests/jvmti/run-tests/test-1967/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1967/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1967DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1968/Android.bp b/hostsidetests/jvmti/run-tests/test-1968/Android.bp
index 1b57bf6..8b38e1c 100644
--- a/hostsidetests/jvmti/run-tests/test-1968/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1968/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1968DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1969/Android.bp b/hostsidetests/jvmti/run-tests/test-1969/Android.bp
index fa5c6df..ab5fcc5 100644
--- a/hostsidetests/jvmti/run-tests/test-1969/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1969/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1969DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1970/Android.bp b/hostsidetests/jvmti/run-tests/test-1970/Android.bp
index 94e1d9a..71bf089 100644
--- a/hostsidetests/jvmti/run-tests/test-1970/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1970/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1970DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1971/Android.bp b/hostsidetests/jvmti/run-tests/test-1971/Android.bp
index 1ac9d3a..6f053ef 100644
--- a/hostsidetests/jvmti/run-tests/test-1971/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1971/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1971DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1974/Android.bp b/hostsidetests/jvmti/run-tests/test-1974/Android.bp
index d1ccbe3..e3b8d7d 100644
--- a/hostsidetests/jvmti/run-tests/test-1974/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1974/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1974DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1975/Android.bp b/hostsidetests/jvmti/run-tests/test-1975/Android.bp
index 1d72113..3c1443e 100644
--- a/hostsidetests/jvmti/run-tests/test-1975/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1975/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1975DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1976/Android.bp b/hostsidetests/jvmti/run-tests/test-1976/Android.bp
index fba22ee..3e624f8 100644
--- a/hostsidetests/jvmti/run-tests/test-1976/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1976/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1976DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1977/Android.bp b/hostsidetests/jvmti/run-tests/test-1977/Android.bp
index 0b70b9a..d1ad972 100644
--- a/hostsidetests/jvmti/run-tests/test-1977/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1977/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1977DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1978/Android.bp b/hostsidetests/jvmti/run-tests/test-1978/Android.bp
index 62bda0d..4e44e31 100644
--- a/hostsidetests/jvmti/run-tests/test-1978/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1978/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1978DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1979/Android.bp b/hostsidetests/jvmti/run-tests/test-1979/Android.bp
index 8f26f89..fc810fb 100644
--- a/hostsidetests/jvmti/run-tests/test-1979/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1979/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1979DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1981/Android.bp b/hostsidetests/jvmti/run-tests/test-1981/Android.bp
index 510e0aa..8620895 100644
--- a/hostsidetests/jvmti/run-tests/test-1981/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1981/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1981DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1982/Android.bp b/hostsidetests/jvmti/run-tests/test-1982/Android.bp
index 9e070ff7..1354fa9 100644
--- a/hostsidetests/jvmti/run-tests/test-1982/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1982/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1982DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1983/Android.bp b/hostsidetests/jvmti/run-tests/test-1983/Android.bp
index d165fd1..ff7a8d9 100644
--- a/hostsidetests/jvmti/run-tests/test-1983/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1983/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1983DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1984/Android.bp b/hostsidetests/jvmti/run-tests/test-1984/Android.bp
index e84c4a8..153a44b 100644
--- a/hostsidetests/jvmti/run-tests/test-1984/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1984/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1984DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1988/Android.bp b/hostsidetests/jvmti/run-tests/test-1988/Android.bp
index 13e6657..9df236f 100644
--- a/hostsidetests/jvmti/run-tests/test-1988/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1988/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1988DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1989/Android.bp b/hostsidetests/jvmti/run-tests/test-1989/Android.bp
index d2420c7..e500ae2 100644
--- a/hostsidetests/jvmti/run-tests/test-1989/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1989/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1989DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1990/Android.bp b/hostsidetests/jvmti/run-tests/test-1990/Android.bp
index 8c953f3..63207b0 100644
--- a/hostsidetests/jvmti/run-tests/test-1990/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1990/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1990DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1991/Android.bp b/hostsidetests/jvmti/run-tests/test-1991/Android.bp
index 216de8b..de6f046 100644
--- a/hostsidetests/jvmti/run-tests/test-1991/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1991/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1991DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1992/Android.bp b/hostsidetests/jvmti/run-tests/test-1992/Android.bp
index 1fc7f43..89643ec 100644
--- a/hostsidetests/jvmti/run-tests/test-1992/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1992/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1992DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1994/Android.bp b/hostsidetests/jvmti/run-tests/test-1994/Android.bp
index 90c4e59..68b67ba 100644
--- a/hostsidetests/jvmti/run-tests/test-1994/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1994/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1994DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1995/Android.bp b/hostsidetests/jvmti/run-tests/test-1995/Android.bp
index 8561296..348d1b0 100644
--- a/hostsidetests/jvmti/run-tests/test-1995/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1995/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1995DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1996/Android.bp b/hostsidetests/jvmti/run-tests/test-1996/Android.bp
index bc17d45..bf26ada 100644
--- a/hostsidetests/jvmti/run-tests/test-1996/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1996/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1996DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1997/Android.bp b/hostsidetests/jvmti/run-tests/test-1997/Android.bp
index 266e3b3..23f35b5 100644
--- a/hostsidetests/jvmti/run-tests/test-1997/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1997/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1997DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1998/Android.bp b/hostsidetests/jvmti/run-tests/test-1998/Android.bp
index c3d57f1..8d39f5d 100644
--- a/hostsidetests/jvmti/run-tests/test-1998/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1998/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1998DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-1999/Android.bp b/hostsidetests/jvmti/run-tests/test-1999/Android.bp
index 364f2d8..d99c359 100644
--- a/hostsidetests/jvmti/run-tests/test-1999/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-1999/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest1999DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-2001/Android.bp b/hostsidetests/jvmti/run-tests/test-2001/Android.bp
index 8288395..ce54c3c 100644
--- a/hostsidetests/jvmti/run-tests/test-2001/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-2001/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest2001DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-2002/Android.bp b/hostsidetests/jvmti/run-tests/test-2002/Android.bp
index 1a2138d..7ba683f 100644
--- a/hostsidetests/jvmti/run-tests/test-2002/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-2002/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest2002DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-2003/Android.bp b/hostsidetests/jvmti/run-tests/test-2003/Android.bp
index 798ae8e..19f40de 100644
--- a/hostsidetests/jvmti/run-tests/test-2003/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-2003/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest2003DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-2004/Android.bp b/hostsidetests/jvmti/run-tests/test-2004/Android.bp
index 2926764..997d6c7 100644
--- a/hostsidetests/jvmti/run-tests/test-2004/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-2004/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest2004DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-2005/Android.bp b/hostsidetests/jvmti/run-tests/test-2005/Android.bp
index 47af189..51bbed0 100644
--- a/hostsidetests/jvmti/run-tests/test-2005/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-2005/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest2005DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-2006/Android.bp b/hostsidetests/jvmti/run-tests/test-2006/Android.bp
index 8b0ad46..bf25e77 100644
--- a/hostsidetests/jvmti/run-tests/test-2006/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-2006/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest2006DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-2007/Android.bp b/hostsidetests/jvmti/run-tests/test-2007/Android.bp
index b320fbf..7df2310 100644
--- a/hostsidetests/jvmti/run-tests/test-2007/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-2007/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest2007DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-902/Android.bp b/hostsidetests/jvmti/run-tests/test-902/Android.bp
index 2299052..9daff3e 100644
--- a/hostsidetests/jvmti/run-tests/test-902/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-902/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest902DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-903/Android.bp b/hostsidetests/jvmti/run-tests/test-903/Android.bp
index 615f57a..c02dc5a 100644
--- a/hostsidetests/jvmti/run-tests/test-903/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-903/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest903DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-904/Android.bp b/hostsidetests/jvmti/run-tests/test-904/Android.bp
index ce0eeaa..27ad801 100644
--- a/hostsidetests/jvmti/run-tests/test-904/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-904/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest904DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-905/Android.bp b/hostsidetests/jvmti/run-tests/test-905/Android.bp
index cd2c248..752c9b4 100644
--- a/hostsidetests/jvmti/run-tests/test-905/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-905/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest905DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-906/Android.bp b/hostsidetests/jvmti/run-tests/test-906/Android.bp
index 8491820..de13556 100644
--- a/hostsidetests/jvmti/run-tests/test-906/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-906/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest906DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-907/Android.bp b/hostsidetests/jvmti/run-tests/test-907/Android.bp
index 518fc7d..9a396c1 100644
--- a/hostsidetests/jvmti/run-tests/test-907/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-907/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest907DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-908/Android.bp b/hostsidetests/jvmti/run-tests/test-908/Android.bp
index aef930a..a2d36ec 100644
--- a/hostsidetests/jvmti/run-tests/test-908/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-908/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest908DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-910/Android.bp b/hostsidetests/jvmti/run-tests/test-910/Android.bp
index cc46813..788e77f 100644
--- a/hostsidetests/jvmti/run-tests/test-910/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-910/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest910DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-911/Android.bp b/hostsidetests/jvmti/run-tests/test-911/Android.bp
index 156aa0d..02ed50a 100644
--- a/hostsidetests/jvmti/run-tests/test-911/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-911/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest911DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-912/Android.bp b/hostsidetests/jvmti/run-tests/test-912/Android.bp
index 8ff1bec..d87675f 100644
--- a/hostsidetests/jvmti/run-tests/test-912/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-912/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest912DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-913/Android.bp b/hostsidetests/jvmti/run-tests/test-913/Android.bp
index 3ef2747..ebe8f51 100644
--- a/hostsidetests/jvmti/run-tests/test-913/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-913/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest913DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-914/Android.bp b/hostsidetests/jvmti/run-tests/test-914/Android.bp
index ac7be56..c6637c6 100644
--- a/hostsidetests/jvmti/run-tests/test-914/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-914/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest914DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-915/Android.bp b/hostsidetests/jvmti/run-tests/test-915/Android.bp
index 7e778d8..92d8dc6 100644
--- a/hostsidetests/jvmti/run-tests/test-915/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-915/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest915DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-917/Android.bp b/hostsidetests/jvmti/run-tests/test-917/Android.bp
index cef34ce..0bad49b 100644
--- a/hostsidetests/jvmti/run-tests/test-917/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-917/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest917DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-918/Android.bp b/hostsidetests/jvmti/run-tests/test-918/Android.bp
index d6a2f08..a406e09 100644
--- a/hostsidetests/jvmti/run-tests/test-918/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-918/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest918DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-919/Android.bp b/hostsidetests/jvmti/run-tests/test-919/Android.bp
index f3c5c53..dbcf34f 100644
--- a/hostsidetests/jvmti/run-tests/test-919/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-919/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest919DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-920/Android.bp b/hostsidetests/jvmti/run-tests/test-920/Android.bp
index b2fb207..373f5bf 100644
--- a/hostsidetests/jvmti/run-tests/test-920/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-920/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest920DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-922/Android.bp b/hostsidetests/jvmti/run-tests/test-922/Android.bp
index d43497e..487d977 100644
--- a/hostsidetests/jvmti/run-tests/test-922/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-922/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest922DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-923/Android.bp b/hostsidetests/jvmti/run-tests/test-923/Android.bp
index e9e9165..b4ebf50 100644
--- a/hostsidetests/jvmti/run-tests/test-923/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-923/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest923DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-924/Android.bp b/hostsidetests/jvmti/run-tests/test-924/Android.bp
index 383a611..c300102 100644
--- a/hostsidetests/jvmti/run-tests/test-924/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-924/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest924DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-926/Android.bp b/hostsidetests/jvmti/run-tests/test-926/Android.bp
index c60de12..04cb340 100644
--- a/hostsidetests/jvmti/run-tests/test-926/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-926/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest926DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-927/Android.bp b/hostsidetests/jvmti/run-tests/test-927/Android.bp
index 812e67a..bccfb1d 100644
--- a/hostsidetests/jvmti/run-tests/test-927/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-927/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest927DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-928/Android.bp b/hostsidetests/jvmti/run-tests/test-928/Android.bp
index 0745805..7aa4dd4 100644
--- a/hostsidetests/jvmti/run-tests/test-928/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-928/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest928DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-930/Android.bp b/hostsidetests/jvmti/run-tests/test-930/Android.bp
index baf38d3..5f4bcb7 100644
--- a/hostsidetests/jvmti/run-tests/test-930/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-930/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest930DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-931/Android.bp b/hostsidetests/jvmti/run-tests/test-931/Android.bp
index fd401d1..516519c 100644
--- a/hostsidetests/jvmti/run-tests/test-931/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-931/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest931DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-932/Android.bp b/hostsidetests/jvmti/run-tests/test-932/Android.bp
index 46936c3..73657da 100644
--- a/hostsidetests/jvmti/run-tests/test-932/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-932/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest932DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-940/Android.bp b/hostsidetests/jvmti/run-tests/test-940/Android.bp
index 72d9821..da39577 100644
--- a/hostsidetests/jvmti/run-tests/test-940/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-940/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest940DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-942/Android.bp b/hostsidetests/jvmti/run-tests/test-942/Android.bp
index fde1311..594f5fb 100644
--- a/hostsidetests/jvmti/run-tests/test-942/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-942/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest942DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-944/Android.bp b/hostsidetests/jvmti/run-tests/test-944/Android.bp
index 5969e42..a641cf5 100644
--- a/hostsidetests/jvmti/run-tests/test-944/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-944/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest944DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-945/Android.bp b/hostsidetests/jvmti/run-tests/test-945/Android.bp
index 0dbe30c..85c1f63 100644
--- a/hostsidetests/jvmti/run-tests/test-945/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-945/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest945DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-947/Android.bp b/hostsidetests/jvmti/run-tests/test-947/Android.bp
index e14c59b..5858dd8 100644
--- a/hostsidetests/jvmti/run-tests/test-947/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-947/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest947DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-951/Android.bp b/hostsidetests/jvmti/run-tests/test-951/Android.bp
index b6dae71..59dfabd 100644
--- a/hostsidetests/jvmti/run-tests/test-951/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-951/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest951DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-982/Android.bp b/hostsidetests/jvmti/run-tests/test-982/Android.bp
index c62b999..91730d2 100644
--- a/hostsidetests/jvmti/run-tests/test-982/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-982/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest982DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-983/Android.bp b/hostsidetests/jvmti/run-tests/test-983/Android.bp
index ed80849..f642f782 100644
--- a/hostsidetests/jvmti/run-tests/test-983/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-983/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest983DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-984/Android.bp b/hostsidetests/jvmti/run-tests/test-984/Android.bp
index 67dba15..0c4bf7b 100644
--- a/hostsidetests/jvmti/run-tests/test-984/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-984/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest984DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-985/Android.bp b/hostsidetests/jvmti/run-tests/test-985/Android.bp
index 91452c7..7179bd1 100644
--- a/hostsidetests/jvmti/run-tests/test-985/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-985/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest985DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-986/Android.bp b/hostsidetests/jvmti/run-tests/test-986/Android.bp
index cfd9166..3b3856b 100644
--- a/hostsidetests/jvmti/run-tests/test-986/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-986/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest986DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-988/Android.bp b/hostsidetests/jvmti/run-tests/test-988/Android.bp
index 17dcb75..bcfecc4 100644
--- a/hostsidetests/jvmti/run-tests/test-988/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-988/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest988DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-989/Android.bp b/hostsidetests/jvmti/run-tests/test-989/Android.bp
index 0f99abc..414fb67 100644
--- a/hostsidetests/jvmti/run-tests/test-989/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-989/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest989DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-990/Android.bp b/hostsidetests/jvmti/run-tests/test-990/Android.bp
index 7f84835..eba9398 100644
--- a/hostsidetests/jvmti/run-tests/test-990/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-990/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest990DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-991/Android.bp b/hostsidetests/jvmti/run-tests/test-991/Android.bp
index a7d6d5c..89c5587 100644
--- a/hostsidetests/jvmti/run-tests/test-991/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-991/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest991DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-992/Android.bp b/hostsidetests/jvmti/run-tests/test-992/Android.bp
index bdb9f9c..5cd0f63 100644
--- a/hostsidetests/jvmti/run-tests/test-992/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-992/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest992DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-993/Android.bp b/hostsidetests/jvmti/run-tests/test-993/Android.bp
index 37b1cc0..e7e50e4 100644
--- a/hostsidetests/jvmti/run-tests/test-993/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-993/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest993DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-994/Android.bp b/hostsidetests/jvmti/run-tests/test-994/Android.bp
index 63fc348..b8727f1 100644
--- a/hostsidetests/jvmti/run-tests/test-994/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-994/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest994DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-995/Android.bp b/hostsidetests/jvmti/run-tests/test-995/Android.bp
index 818d938..2f1a65a 100644
--- a/hostsidetests/jvmti/run-tests/test-995/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-995/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest995DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-996/Android.bp b/hostsidetests/jvmti/run-tests/test-996/Android.bp
index 5c80177..e4fa057 100644
--- a/hostsidetests/jvmti/run-tests/test-996/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-996/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest996DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/run-tests/test-997/Android.bp b/hostsidetests/jvmti/run-tests/test-997/Android.bp
index 719d51a..89ab9e5 100644
--- a/hostsidetests/jvmti/run-tests/test-997/Android.bp
+++ b/hostsidetests/jvmti/run-tests/test-997/Android.bp
@@ -25,4 +25,7 @@
"general-tests",
],
data: [":CtsJvmtiRunTest997DeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/jvmti/tagging/Android.bp b/hostsidetests/jvmti/tagging/Android.bp
index 32c262c..9571914 100644
--- a/hostsidetests/jvmti/tagging/Android.bp
+++ b/hostsidetests/jvmti/tagging/Android.bp
@@ -26,4 +26,7 @@
"general-tests",
],
data: [":CtsJvmtiTaggingDeviceApp"],
-}
+ test_options: {
+ unit_test: false,
+ },
+}
\ No newline at end of file
diff --git a/hostsidetests/os/OWNERS b/hostsidetests/os/OWNERS
index 9abffa5..d4251a9 100644
--- a/hostsidetests/os/OWNERS
+++ b/hostsidetests/os/OWNERS
@@ -3,4 +3,5 @@
santoscordon@google.com
per-file InattentiveSleepTests.java=rgl@google.com, robhor@google.com
per-file QuiescentBootTests.java=rgl@google.com, robhor@google.com
+per-file StaticSharedLibsHostTests.java=patb@google.com
diff --git a/hostsidetests/os/test-apps/OWNERS b/hostsidetests/os/test-apps/OWNERS
new file mode 100644
index 0000000..0f08fe3
--- /dev/null
+++ b/hostsidetests/os/test-apps/OWNERS
@@ -0,0 +1,16 @@
+per-file StaticSharedLibConsumerApp1/*=patb@google.com
+per-file StaticSharedLibConsumerApp2/*=patb@google.com
+per-file StaticSharedLibConsumerApp3/*=patb@google.com
+per-file StaticSharedLibProviderApp1/*=patb@google.com
+per-file StaticSharedLibProviderApp2/*=patb@google.com
+per-file StaticSharedLibProviderApp3/*=patb@google.com
+per-file StaticSharedLibProviderApp4/*=patb@google.com
+per-file StaticSharedLibProviderApp5/*=patb@google.com
+per-file StaticSharedLibProviderApp6/*=patb@google.com
+per-file StaticSharedLibProviderApp7/*=patb@google.com
+per-file StaticSharedLibProviderAppRecursive/*=patb@google.com
+per-file StaticSharedLibTestApp/*=patb@google.com
+per-file StaticSharedNativeLibConsumer/*=patb@google.com
+per-file StaticSharedNativeLibProvider/*=patb@google.com
+per-file StaticSharedNativeLibProvider1/*=patb@google.com
+
diff --git a/hostsidetests/seccomp/app/jni/android_seccomp_cts_app_SeccompDeviceTest.cpp b/hostsidetests/seccomp/app/jni/android_seccomp_cts_app_SeccompDeviceTest.cpp
index 99080a1..7a40949 100644
--- a/hostsidetests/seccomp/app/jni/android_seccomp_cts_app_SeccompDeviceTest.cpp
+++ b/hostsidetests/seccomp/app/jni/android_seccomp_cts_app_SeccompDeviceTest.cpp
@@ -29,8 +29,6 @@
#define ALOGI(...) ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)
#define ALOGE(...) ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)
-#define PER_USER_RANGE 100000
-
/*
* Function: testSyscallBlocked
* Purpose: test that the syscall listed is blocked by seccomp
@@ -79,21 +77,17 @@
}
static jboolean testSetresuidBlocked(JNIEnv *, jobject, jint ruid, jint euid, jint suid) {
- jint userId = getuid() / PER_USER_RANGE;
- jint userRuid = userId * PER_USER_RANGE + ruid;
- jint userEuid = userId * PER_USER_RANGE + euid;
- jint userSuid = userId * PER_USER_RANGE + suid;
-
- return doTestSyscallBlocked([&] {ALOGE("Calling setresuid\n"); setresuid(userRuid, userEuid, userSuid);});
+ return doTestSyscallBlocked([&] {
+ ALOGE("Calling setresuid\n");
+ setresuid(ruid, euid, suid);
+ });
}
static jboolean testSetresgidBlocked(JNIEnv *, jobject, jint rgid, jint egid, jint sgid) {
- jint userId = getuid() / PER_USER_RANGE;
- jint userRgid = userId * PER_USER_RANGE + rgid;
- jint userEgid = userId * PER_USER_RANGE + egid;
- jint userSgid = userId * PER_USER_RANGE + sgid;
-
- return doTestSyscallBlocked([&] {ALOGE("Calling setresgid\n"); setresgid(userRgid, userEgid, userSgid);});
+ return doTestSyscallBlocked([&] {
+ ALOGE("Calling setresgid\n");
+ setresgid(rgid, egid, sgid);
+ });
}
static JNINativeMethod gMethods[] = {
diff --git a/hostsidetests/seccomp/app/src/android/seccomp/cts/app/ZygotePreload.java b/hostsidetests/seccomp/app/src/android/seccomp/cts/app/ZygotePreload.java
index fe6053b..021b56b 100644
--- a/hostsidetests/seccomp/app/src/android/seccomp/cts/app/ZygotePreload.java
+++ b/hostsidetests/seccomp/app/src/android/seccomp/cts/app/ZygotePreload.java
@@ -18,6 +18,7 @@
import android.content.pm.ApplicationInfo;
import android.os.Process;
+import android.os.UserHandle;
import android.util.Log;
public class ZygotePreload implements android.app.ZygotePreload {
@@ -26,38 +27,41 @@
static volatile boolean sResult = false;
static volatile int sStartOfIsolatedRange = -1;
- static private boolean testSetResUidGidBlocked(int rid, int eid, int sid) {
- if (!SeccompDeviceTest.testSetresuidBlocked(rid, eid, sid)) {
- Log.e(TAG, "setresuid( " + Integer.toString(rid) + ","
- + Integer.toString(eid) + "," + Integer.toString(sid) + ")"
- + " is wrongly allowed.");
+ static private boolean testSetResUidGidBlocked(int rid, int eid, int sid,
+ boolean expectBlocked, boolean log) {
+ boolean blocked = SeccompDeviceTest.testSetresuidBlocked(rid, eid, sid);
+ if (blocked != expectBlocked) {
+ if (log) {
+ Log.e(TAG, "setresuid( " + Integer.toString(rid) + ","
+ + Integer.toString(eid) + "," + Integer.toString(sid) + ")"
+ + " is wrongly " + (expectBlocked ? "allowed." : "blocked."));
+ }
return false;
}
- if (!SeccompDeviceTest.testSetresgidBlocked(rid, eid, sid)) {
- Log.e(TAG, "setresguid( " + Integer.toString(rid) + ","
- + Integer.toString(eid) + "," + Integer.toString(sid) + ")"
- + " is wrongly allowed.");
+
+ blocked = SeccompDeviceTest.testSetresgidBlocked(rid, eid, sid);
+ if (blocked != expectBlocked) {
+ if (log) {
+ Log.e(TAG, "setresguid( " + Integer.toString(rid) + ","
+ + Integer.toString(eid) + "," + Integer.toString(sid) + ")"
+ + " is wrongly " + (expectBlocked ? "allowed." : "blocked."));
+ }
return false;
}
return true;
}
- static private boolean testSetResUidGidAllowed(int rid, int eid, int sid) {
- if (SeccompDeviceTest.testSetresuidBlocked(rid, eid, sid)) {
- Log.e(TAG, "setresuid( " + Integer.toString(rid) + ","
- + Integer.toString(eid) + "," + Integer.toString(sid) + ")"
- + " is wrongly blocked.");
- return false;
- }
- if (SeccompDeviceTest.testSetresgidBlocked(rid, eid, sid)) {
- Log.e(TAG, "setresguid( " + Integer.toString(rid) + ","
- + Integer.toString(eid) + "," + Integer.toString(sid) + ")"
- + " is wrongly blocked.");
- return false;
- }
+ static private boolean testSetResUidGidBlocked(int rid, int eid, int sid) {
+ return testSetResUidGidBlocked(rid, eid, sid, true /*expectBlocked */, true /* log */);
+ }
- return true;
+ static private boolean testSetResUidGidAllowed(int rid, int eid, int sid) {
+ return testSetResUidGidBlocked(rid, eid, sid, false /*expectBlocked */, true /* log */);
+ }
+
+ static private boolean testSetResUidGidAllowedNoLog(int rid, int eid, int sid) {
+ return testSetResUidGidBlocked(rid, eid, sid, false /*expectBlocked */, false /* log */);
}
static synchronized public boolean getSeccomptestResult() {
@@ -90,25 +94,35 @@
result &= testSetResUidGidBlocked(0, Process.SYSTEM_UID,
Process.SYSTEM_UID);
- // an app uid
- result &= testSetResUidGidBlocked(Process.FIRST_APPLICATION_UID,
- Process.FIRST_APPLICATION_UID, Process.FIRST_APPLICATION_UID);
- result &= testSetResUidGidBlocked(Process.LAST_APPLICATION_UID,
- Process.LAST_APPLICATION_UID, Process.LAST_APPLICATION_UID);
+ // an app uid for the current user, and another user
+ for (int userId = UserHandle.myUserId(); userId <= UserHandle.myUserId() + 1; userId++) {
+ int appStart = UserHandle.getUid(userId, Process.FIRST_APPLICATION_UID);
+ result &= testSetResUidGidBlocked(appStart, appStart, appStart);
+ int appEnd = UserHandle.getUid(userId, Process.LAST_APPLICATION_UID);
+ result &= testSetResUidGidBlocked(appEnd, appEnd, appEnd);
+ }
- // an isolated process uid
- result &= testSetResUidGidBlocked(Process.FIRST_ISOLATED_UID,
- Process.FIRST_ISOLATED_UID, Process.FIRST_ISOLATED_UID);
- result &= testSetResUidGidBlocked(Process.LAST_ISOLATED_UID, Process.LAST_ISOLATED_UID,
- Process.LAST_ISOLATED_UID);
+ // an isolated process uid for the current user, and another user
+ for (int userId = UserHandle.myUserId(); userId <= UserHandle.myUserId() + 1; userId++) {
+ int regularIsolatedStart = UserHandle.getUid(userId, Process.FIRST_ISOLATED_UID);
+ result &= testSetResUidGidBlocked(regularIsolatedStart, regularIsolatedStart,
+ regularIsolatedStart);
+ int regularIsolatedEnd = UserHandle.getUid(userId, Process.LAST_ISOLATED_UID);
+ result &= testSetResUidGidBlocked(regularIsolatedEnd, regularIsolatedEnd,
+ regularIsolatedEnd);
+ }
// Test all ranges of app zygote UIDs; we don't know here which
// isolated UID is assigned to our process, so we will test all ranges,
// and verify only one is allowed; then have the caller verify that
// this was indeed our allowed range.
- for (int i = Process.FIRST_APP_ZYGOTE_ISOLATED_UID;
- i < Process.LAST_APP_ZYGOTE_ISOLATED_UID; i += Process.NUM_UIDS_PER_APP_ZYGOTE) {
- boolean rangeAllowed = testSetResUidGidAllowed(i, i, i);
+ int isolatedUserStart = UserHandle.getUid(UserHandle.myUserId(),
+ Process.FIRST_APP_ZYGOTE_ISOLATED_UID);
+ int isolatedUserEnd = UserHandle.getUid(UserHandle.myUserId(),
+ Process.LAST_APP_ZYGOTE_ISOLATED_UID);
+
+ for (int i = isolatedUserStart; i < isolatedUserEnd; i += Process.NUM_UIDS_PER_APP_ZYGOTE) {
+ boolean rangeAllowed = testSetResUidGidAllowedNoLog(i, i, i);
if (rangeAllowed) {
if (sStartOfIsolatedRange != -1) {
Log.e(TAG, "Found more than one allowed isolated UID range: "
@@ -137,7 +151,6 @@
}
}
- // one over the range
result &= testSetResUidGidBlocked(Process.LAST_APP_ZYGOTE_ISOLATED_UID + 1,
Process.LAST_APP_ZYGOTE_ISOLATED_UID + 1, Process.LAST_APP_ZYGOTE_ISOLATED_UID + 1);
diff --git a/hostsidetests/security/src/android/security/cts/KernelConfigTest.java b/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
index 6de6044..0b0a84b 100644
--- a/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
+++ b/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
@@ -249,6 +249,36 @@
put("mt6873", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
put("MT6853V/TZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
put("MT6853V/TNZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6833V/ZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6833V/NZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6833V/TZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6833V/TNZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6833V/MZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6833V/MNZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6877V/ZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6877V/NZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6877V/TZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6877V/TNZA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6768V/WA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6768V/CA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6768V/WB", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6768V/CB", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6767V/WA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6767V/CA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6767V/WB", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6767V/CB", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6769V/WA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6769V/CA", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6769V/WB", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6769V/CB", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6769V/WT", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6769V/CT", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6769V/WU", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6769V/CU", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6769V/WZ", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6769V/CZ", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6769V/WY", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
+ put("MT6769V/CY", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
put("SDMMAGPIE", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
put("SM6150", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
put("SM7150", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
@@ -264,6 +294,7 @@
put("QM215", null);
put("ATOLL", null);
put("ATOLL-AB", null);
+ put("SDM660", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
put("BENGAL", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
put("DEFAULT", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y",
"CONFIG_UNMAP_KERNEL_AT_EL0=y"});
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index 382c931..9fb00d9 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -82,6 +82,7 @@
private static final String VINTF_DEVICE_JSON = VINTF_DEVICE_CLASS + DEVICE_INFO_SUFFIX;
// Keep in sync with com.android.compatibility.common.deviceinfo.VintfDeviceInfo
private static final String SEPOLICY_VERSION_JSON_KEY = "sepolicy_version";
+ private static final String PLATFORM_SEPOLICY_VERSION_JSON_KEY = "platform_sepolicy_version";
private static final Map<ITestDevice, File> cachedDevicePolicyFiles = new HashMap<>(1);
private static final Map<ITestDevice, File> cachedDevicePlatFcFiles = new HashMap<>(1);
@@ -239,6 +240,8 @@
File systemSepolicyCilFile = File.createTempFile("plat_sepolicy", ".cil");
systemSepolicyCilFile.deleteOnExit();
+ File fileContextsFile = File.createTempFile("file_contexts", ".txt");
+ fileContextsFile.deleteOnExit();
assertTrue(device.pullFile("/system/etc/selinux/plat_sepolicy.cil", systemSepolicyCilFile));
@@ -246,6 +249,7 @@
secilc.getAbsolutePath(),
"-m", "-M", "true", "-c", "30",
"-o", builtPolicyFile.getAbsolutePath(),
+ "-f", fileContextsFile.getAbsolutePath(),
systemSepolicyCilFile.getAbsolutePath());
pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
pb.redirectErrorStream(true);
@@ -345,7 +349,7 @@
String content = FileUtil.readStringFromFile(vintfJson);
JSONObject object = new JSONObject(content);
String version = object.getString(SEPOLICY_VERSION_JSON_KEY);
- return getVendorSepolicyVersionFromMajorMinor(version);
+ return getSepolicyVersionFromMajorMinor(version);
}
/**
@@ -368,13 +372,26 @@
Element root = doc.getDocumentElement();
Element sepolicy = (Element) root.getElementsByTagName("sepolicy").item(0);
Element version = (Element) sepolicy.getElementsByTagName("version").item(0);
- return getVendorSepolicyVersionFromMajorMinor(version.getTextContent());
+ return getSepolicyVersionFromMajorMinor(version.getTextContent());
+ }
+
+ // NOTE: cts/tools/selinux depends on this method. Rename/change with caution.
+ /**
+ * Returns the major number of sepolicy version of system.
+ */
+ public static int getSystemSepolicyVersion(IBuildInfo build) throws Exception {
+ File deviceInfoDir = build.getFile(DeviceInfoCollector.DEVICE_INFO_DIR);
+ File vintfJson = deviceInfoDir.toPath().resolve(VINTF_DEVICE_JSON).toFile();
+ String content = FileUtil.readStringFromFile(vintfJson);
+ JSONObject object = new JSONObject(content);
+ String version = object.getString(PLATFORM_SEPOLICY_VERSION_JSON_KEY);
+ return getSepolicyVersionFromMajorMinor(version);
}
/**
* Get the major number from an SEPolicy version string, e.g. "27.0" => 27.
*/
- private static int getVendorSepolicyVersionFromMajorMinor(String version) {
+ private static int getSepolicyVersionFromMajorMinor(String version) {
String sepolicyVersion = version.split("\\.")[0];
return Integer.parseInt(sepolicyVersion);
}
@@ -977,6 +994,26 @@
}
/**
+ * Tests that tracefs files(/sys/kernel/tracing and /d/tracing) are correctly labeled.
+ *
+ * @throws Exception
+ */
+ public void testTracefsTypeViolators() throws Exception {
+ assertSepolicyTests("TestTracefsTypeViolations", "/sepolicy_tests",
+ PropertyUtil.isVendorApiLevelNewerThan(mDevice, 30) /* includeVendorSepolicy */);
+ }
+
+ /**
+ * Tests that debugfs files(from /sys/kernel/debug) are correctly labeled.
+ *
+ * @throws Exception
+ */
+ public void testDebugfsTypeViolators() throws Exception {
+ assertSepolicyTests("TestDebugfsTypeViolations", "/sepolicy_tests",
+ PropertyUtil.isVendorApiLevelNewerThan(mDevice, 30) /* includeVendorSepolicy */);
+ }
+
+ /**
* Tests that all domains with entrypoints on /system have the coredomain
* attribute, and that all domains with entrypoints on /vendor do not have the
* coredomain attribute.
@@ -1295,7 +1332,7 @@
/* keystore is always running */
@CddTest(requirement="9.7")
public void testKeystoreDomain() throws DeviceNotAvailableException {
- assertDomainOne("u:r:keystore:s0", "/system/bin/keystore");
+ assertDomainOne("u:r:keystore:s0", "/system/bin/keystore2");
}
/* System server better be running :-P */
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/Android.bp
deleted file mode 100644
index f4554af..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/Android.bp
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-cc_test {
- name: "CVE-2020-0408",
- defaults: ["cts_hostsidetests_securitybulletin_defaults"],
- srcs: ["poc.cpp"],
- shared_libs: [
- "libutils",
- ],
-}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/poc.cpp
deleted file mode 100644
index dcccd2e..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0408/poc.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "utils/String16.h"
-
-int main(void) {
- android::String16 str{u"hello world"};
- android::String16 substr{u"hello"};
- const size_t begin = substr.size();
- const size_t len = std::numeric_limits<size_t>::max();
- if (str.remove(len, begin) != android::OK) {
- return EXIT_FAILURE;
- }
- if (strcmp16(str, substr) != 0) {
- return EXIT_FAILURE;
- }
- return EXIT_SUCCESS;
-}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0450/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0450/poc.cpp
index 268153b..0499a84 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0450/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0450/poc.cpp
@@ -41,43 +41,6 @@
void *kVulnPtr = nullptr;
uint16_t kVulnSize = 0;
-// borrowed from rw_i93.cc
-enum {
- RW_I93_STATE_NOT_ACTIVATED, /* ISO15693 is not activated */
- RW_I93_STATE_IDLE, /* waiting for upper layer API */
- RW_I93_STATE_BUSY, /* waiting for response from tag */
-
- RW_I93_STATE_DETECT_NDEF, /* performing NDEF detection precedure */
- RW_I93_STATE_READ_NDEF, /* performing read NDEF procedure */
- RW_I93_STATE_UPDATE_NDEF, /* performing update NDEF procedure */
- RW_I93_STATE_FORMAT, /* performing format procedure */
- RW_I93_STATE_SET_READ_ONLY, /* performing set read-only procedure */
-
- RW_I93_STATE_PRESENCE_CHECK /* checking presence of tag */
-};
-
-// borrowed from rw_i93.cc
-enum {
- RW_I93_SUBSTATE_WAIT_UID, /* waiting for response of inventory */
- RW_I93_SUBSTATE_WAIT_SYS_INFO, /* waiting for response of get sys info */
- RW_I93_SUBSTATE_WAIT_CC, /* waiting for reading CC */
- RW_I93_SUBSTATE_SEARCH_NDEF_TLV, /* searching NDEF TLV */
- RW_I93_SUBSTATE_CHECK_LOCK_STATUS, /* check if any NDEF TLV is locked */
-
- RW_I93_SUBSTATE_RESET_LEN, /* set length to 0 to update NDEF TLV */
- RW_I93_SUBSTATE_WRITE_NDEF, /* writing NDEF and Terminator TLV */
- RW_I93_SUBSTATE_UPDATE_LEN, /* set length into NDEF TLV */
-
- RW_I93_SUBSTATE_WAIT_RESET_DSFID_AFI, /* reset DSFID and AFI */
- RW_I93_SUBSTATE_CHECK_READ_ONLY, /* check if any block is locked */
- RW_I93_SUBSTATE_WRITE_CC_NDEF_TLV, /* write CC and empty NDEF/Terminator TLV
- */
-
- RW_I93_SUBSTATE_WAIT_UPDATE_CC, /* updating CC as read-only */
- RW_I93_SUBSTATE_LOCK_NDEF_TLV, /* lock blocks of NDEF TLV */
- RW_I93_SUBSTATE_WAIT_LOCK_CC /* lock block of CC */
-};
-
static tNFC_STATUS (*real_rw_i93_send_cmd_write_single_block)(
uint16_t block_number, uint8_t *p_data) = nullptr;
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
index 80fcf24..8acba06 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
@@ -117,21 +117,6 @@
}
/**
- * b/156999009
- * Vulnerability Behaviour: SIGABRT in self
- */
- @SecurityTest(minPatchLevel = "2020-10")
- @Test
- public void testPocCVE_2020_0408() throws Exception {
- String signals[] = {CrashUtils.SIGSEGV, CrashUtils.SIGBUS, CrashUtils.SIGABRT};
- String binaryName = "CVE-2020-0408";
- AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig(binaryName, getDevice());
- testConfig.config = new CrashUtils.Config().setProcessPatterns(binaryName);
- testConfig.config.setSignals(signals);
- AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
- }
-
- /**
* b/161894517
* Vulnerability Behaviour: SIGABRT in self
*/
diff --git a/hostsidetests/stagedinstall/Android.bp b/hostsidetests/stagedinstall/Android.bp
index 8ea3089..e3e84f1 100644
--- a/hostsidetests/stagedinstall/Android.bp
+++ b/hostsidetests/stagedinstall/Android.bp
@@ -66,6 +66,7 @@
":StagedInstallTestCorruptedApex_b146895998",
":StagedInstallTestApexV2_NoApkSignature",
":StagedInstallTestApexV2_UnsignedPayload",
+ ":StagedInstallTestApexV2_SignPayloadWithDifferentKey",
],
static_libs: [
"androidx.test.runner",
@@ -533,6 +534,28 @@
installable: false,
}
+ApexFilenameSigningPayloadWithDifferentKey =
+ "com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex"
+prebuilt_apex {
+ name: "StagedInstallTestApexV2_SignPayloadWithDifferentKey",
+ arch: {
+ arm: {
+ src: "testdata/apex/arm/" + ApexFilenameSigningPayloadWithDifferentKey,
+ },
+ arm64: {
+ src: "testdata/apex/arm/" + ApexFilenameSigningPayloadWithDifferentKey,
+ },
+ x86: {
+ src: "testdata/apex/x86/" + ApexFilenameSigningPayloadWithDifferentKey,
+ },
+ x86_64: {
+ src: "testdata/apex/x86/" + ApexFilenameSigningPayloadWithDifferentKey,
+ },
+ },
+ filename: ApexFilenameSigningPayloadWithDifferentKey,
+ installable: false,
+}
+
// collects deapexer and its dependency modules (libc++ and debugfs_static) to the zip file.
genrule {
name: "deapexer.zip",
diff --git a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
index f61d887..d5af898 100644
--- a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
+++ b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
@@ -157,6 +157,9 @@
private static final TestApp Apex2UnsignedPayload = new TestApp(
"StagedInstallTestApexV2_UnsignedPayload", SHIM_APEX_PACKAGE_NAME, 1,
/*isApex*/true, "com.android.apex.cts.shim.v2_unsigned_payload.apex");
+ private static final TestApp Apex2SignPayloadWithDifferentKey = new TestApp(
+ "StagedInstallTestApexV2_SignPayloadWithDifferentKey", SHIM_APEX_PACKAGE_NAME, 1,
+ /*isApex*/true, "com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex");
@Before
public void adoptShellPermissions() {
@@ -1174,6 +1177,19 @@
}
/**
+ * Should fail to verify apex signed payload with a different key
+ */
+ @Test
+ public void testApexSignPayloadWithDifferentKeyFailsVerification() throws Exception {
+ int sessionId = stageSingleApk(
+ Apex2SignPayloadWithDifferentKey).assertSuccessful().getSessionId();
+ PackageInstaller.SessionInfo sessionInfo = waitForBroadcast(sessionId);
+ assertThat(sessionInfo).isStagedSessionFailed();
+ assertThat(sessionInfo.getStagedSessionErrorMessage())
+ .contains("public key doesn't match the pre-installed one");
+ }
+
+ /**
* Test non-priv apps cannot access /data/app-staging folder contents
*/
@Test
diff --git a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
index 209cb6a..d540536 100644
--- a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
+++ b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
@@ -651,6 +651,16 @@
}
/**
+ * Should fail to verify apex signed payload with a different key
+ */
+ @Test
+ public void testApexSignPayloadWithDifferentKeyFailsVerification() throws Exception {
+ assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported());
+
+ runPhase("testApexSignPayloadWithDifferentKeyFailsVerification");
+ }
+
+ /**
* Should fail to verify apex with unsigned payload
*/
@Test
@@ -668,6 +678,21 @@
runPhase("testAppStagingDirCannotBeReadByNonPrivApps");
}
+ @Test
+ @LargeTest
+ public void testUpdatedApexFromDataApexActiveCanBePulled() throws Exception {
+ assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported());
+
+ installV2Apex();
+
+ final ITestDevice.ApexInfo shimApex = mHostUtils.getShimApex().orElseThrow(
+ () -> new AssertionError("Can't find " + SHIM_APEX_PACKAGE_NAME)
+ );
+
+ assertThat(shimApex.sourceDir).startsWith("/data/apex/active");
+ assertThat(getDevice().pullFile(shimApex.sourceDir)).isNotNull();
+ }
+
/**
* Store the component name of the default launcher. This value will be used to reset the
* default launcher to its correct component upon test completion.
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 7b5758d..519a5e6 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 dc2c8c9..b82b961 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 3cf81757..0558952 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 5335818..f909639 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 4f0edff..4037bd1 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_different_certificate.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_different_certificate.apex
index af89d20..8909a72 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 12b85e4..714ac09 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 00c0c19..b5a1a80 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_no_hashtree.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_no_hashtree.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_sdk_target_p.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_sdk_target_p.apex
index 50e77bd..d7aef82 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_sdk_target_p.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_sdk_target_p.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex
new file mode 100644
index 0000000..3e8a2d6
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v2_signed_bob.apex
index 3bde9ba..30e70bc 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 26c3f27a..de8da11 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 81aaecf..26da4fa 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 d2be4a2..db6f51b 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 e1f904e..b724f0d 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 c8aa9d9..0da0bf9 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 41c29bf..e359b01 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 1447e7d..9c7e747 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 e538f83..8de4b10 100644
--- a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_signed_bob.apex b/hostsidetests/stagedinstall/testdata/apex/arm/com.android.apex.cts.shim.v3_signed_bob.apex
index 86b418e..0ef71fc 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 29a0877..fc8e3e7 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 e8705c7..894e1682 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 04ec92d..fd79365 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 ff54789..a629874 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 3cf81757..0558952 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 5335818..f909639 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 4f0edff..4037bd1 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_apk_in_apex_sdk_target_p.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_different_certificate.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_different_certificate.apex
index af89d20..8909a72 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 eca1c37..183915a 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 19da864..03f484b 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_no_hashtree.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_no_hashtree.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_sdk_target_p.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_sdk_target_p.apex
index 6b7436b..362bed2 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_sdk_target_p.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_sdk_target_p.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex
new file mode 100644
index 0000000..3e8a2d6
--- /dev/null
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_sign_payload_with_different_key.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v2_signed_bob.apex
index 659f462..c66f0a3 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 c5e2210..4c062a1 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 3ff88a9..aef2e04 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 cd702268..28c0893 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 e1f904e..b724f0d 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 c8aa9d9..0da0bf9 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 41c29bf..e359b01 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 1447e7d..9c7e747 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 b3ecef7..6e166d9 100644
--- a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3.apex
Binary files differ
diff --git a/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_signed_bob.apex b/hostsidetests/stagedinstall/testdata/apex/x86/com.android.apex.cts.shim.v3_signed_bob.apex
index 9281ee3..7644bb93 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 23b2378..2d54902 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 e8705c7..894e1682 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 b6afbd0..e910cf6 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 b6afbd0..e910cf6 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/sustainedperf/app/Android.bp b/hostsidetests/sustainedperf/app/Android.bp
new file mode 100644
index 0000000..2413f22
--- /dev/null
+++ b/hostsidetests/sustainedperf/app/Android.bp
@@ -0,0 +1,35 @@
+// 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 {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsSustainedPerformanceDeviceTestApp",
+ dex_preopt: {
+ enabled: false,
+ },
+ optimize: {
+ enabled: false,
+ },
+ srcs: ["src/**/*.java"],
+ // tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+ sdk_version: "current",
+}
diff --git a/hostsidetests/sustainedperf/app/Android.mk b/hostsidetests/sustainedperf/app/Android.mk
deleted file mode 100644
index 473621a..0000000
--- a/hostsidetests/sustainedperf/app/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-
-LOCAL_PACKAGE_NAME := CtsSustainedPerformanceDeviceTestApp
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/hostsidetests/sustainedperf/shadertoy_android/Android.mk b/hostsidetests/sustainedperf/shadertoy_android/Android.mk
index 59cc55f..e85b172 100644
--- a/hostsidetests/sustainedperf/shadertoy_android/Android.mk
+++ b/hostsidetests/sustainedperf/shadertoy_android/Android.mk
@@ -29,6 +29,8 @@
#LOCAL_STATIC_LIBRARIES := libc++_static
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsSustainedPerformanceTestCases
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_SDK_VERSION := current
LOCAL_MIN_SDK_VERSION := 5
diff --git a/hostsidetests/tagging/.clang-format b/hostsidetests/tagging/.clang-format
new file mode 100644
index 0000000..9a22ead
--- /dev/null
+++ b/hostsidetests/tagging/.clang-format
@@ -0,0 +1,6 @@
+BasedOnStyle: Google
+ColumnLimit: 100
+IndentWidth: 2
+AllowShortFunctionsOnASingleLine: Inline
+UseTab: Never
+
diff --git a/hostsidetests/tagging/common/Android.bp b/hostsidetests/tagging/common/Android.bp
index 468940e..147cbde 100644
--- a/hostsidetests/tagging/common/Android.bp
+++ b/hostsidetests/tagging/common/Android.bp
@@ -40,14 +40,10 @@
android_test_helper_app {
name: "DeviceKernelHelpers",
- defaults: ["cts_defaults"],
- compile_multilib: "both",
+ defaults: ["cts_tagging_app_defaults"],
test_suites: [
"cts",
"general-tests",
],
- static_libs: ["tagging-common-devicesidelib"],
- jni_libs: ["libtagging-common-devicesidelib-jni"],
srcs: ["src/**/DeviceKernelHelpers.java"],
- sdk_version: "current",
}
diff --git a/hostsidetests/tagging/common/AndroidManifest.xml b/hostsidetests/tagging/common/AndroidManifest.xml
index 41d0459..dc5ec58 100644
--- a/hostsidetests/tagging/common/AndroidManifest.xml
+++ b/hostsidetests/tagging/common/AndroidManifest.xml
@@ -21,16 +21,11 @@
<application android:debuggable="true"
android:allowNativeHeapPointerTagging="true">
- <activity android:name=".DeviceKernelHelpers">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
+ <uses-library android:name="android.test.runner" />
</application>
<instrumentation
- android:name="android.test.InstrumentationTestRunner"
+ android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="android.cts.tagging.support" />
</manifest>
diff --git a/hostsidetests/tagging/common/jni/android_cts_tagging_Utils.cpp b/hostsidetests/tagging/common/jni/android_cts_tagging_Utils.cpp
index af48ace..05220eb 100644
--- a/hostsidetests/tagging/common/jni/android_cts_tagging_Utils.cpp
+++ b/hostsidetests/tagging/common/jni/android_cts_tagging_Utils.cpp
@@ -14,18 +14,14 @@
* limitations under the License.
*/
-/*
- * Native implementation for the JniStaticTest parts.
- */
-
#include <errno.h>
#include <jni.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/prctl.h>
#include <sys/utsname.h>
-extern "C" JNIEXPORT jboolean
-Java_android_cts_tagging_Utils_kernelSupportsTaggedPointers() {
+extern "C" JNIEXPORT jboolean Java_android_cts_tagging_Utils_kernelSupportsTaggedPointers() {
#ifdef __aarch64__
#define PR_SET_TAGGED_ADDR_CTRL 55
#define PR_TAGGED_ADDR_ENABLE (1UL << 0)
@@ -36,8 +32,7 @@
#endif
}
-extern "C" JNIEXPORT jint JNICALL
-Java_android_cts_tagging_Utils_nativeHeapPointerTag(JNIEnv *) {
+extern "C" JNIEXPORT jint JNICALL Java_android_cts_tagging_Utils_nativeHeapPointerTag(JNIEnv *) {
#ifdef __aarch64__
void *p = malloc(10);
jint tag = reinterpret_cast<uintptr_t>(p) >> 56;
@@ -48,22 +43,41 @@
#endif
}
-extern "C" __attribute__((no_sanitize("address", "hwaddress")))
-JNIEXPORT void JNICALL
+extern "C" __attribute__((no_sanitize("address", "hwaddress"))) JNIEXPORT void JNICALL
Java_android_cts_tagging_Utils_accessMistaggedPointer(JNIEnv *) {
- int* p = new int[4];
- int* mistagged_p = reinterpret_cast<int*>(reinterpret_cast<uintptr_t>(p) + (1ULL << 56));
+ int *p = new int[4];
+ int *mistagged_p = reinterpret_cast<int *>(reinterpret_cast<uintptr_t>(p) + (1ULL << 56));
volatile int load = *mistagged_p;
(void)load;
delete[] p;
}
-extern "C"
-JNIEXPORT jboolean JNICALL
+extern "C" JNIEXPORT jboolean JNICALL
Java_android_cts_tagging_Utils_mistaggedKernelUaccessFails(JNIEnv *) {
auto *p = new utsname;
- utsname* mistagged_p = reinterpret_cast<utsname*>(reinterpret_cast<uintptr_t>(p) + (1ULL << 56));
+ utsname *mistagged_p = reinterpret_cast<utsname *>(reinterpret_cast<uintptr_t>(p) + (1ULL << 56));
bool result = uname(mistagged_p) != 0 && errno == EFAULT;
delete p;
return result;
}
+
+__attribute__((optnone)) static bool sizeIsZeroInitialized(size_t size) {
+ const int kCount = 200;
+ for (int i = 0; i < kCount; ++i) {
+ char *volatile p = reinterpret_cast<char *>(malloc(size));
+ for (int j = 0; j < size; ++j) {
+ if (p[j] != 0) {
+ free(p);
+ return false;
+ }
+ }
+ memset(p, 42, size);
+ free(p);
+ }
+ return true;
+}
+
+extern "C" JNIEXPORT jboolean JNICALL
+Java_android_cts_tagging_Utils_heapIsZeroInitialized(JNIEnv *) {
+ return sizeIsZeroInitialized(100) && sizeIsZeroInitialized(2000) && sizeIsZeroInitialized(200000);
+}
diff --git a/hostsidetests/tagging/common/src/android/cts/tagging/Utils.java b/hostsidetests/tagging/common/src/android/cts/tagging/Utils.java
index dbd62d3..4f5e387 100644
--- a/hostsidetests/tagging/common/src/android/cts/tagging/Utils.java
+++ b/hostsidetests/tagging/common/src/android/cts/tagging/Utils.java
@@ -24,4 +24,6 @@
public static native int nativeHeapPointerTag();
public static native void accessMistaggedPointer();
public static native boolean mistaggedKernelUaccessFails();
+
+ public static native boolean heapIsZeroInitialized();
}
diff --git a/hostsidetests/tagging/common/src/android/cts/tagging/support/DeviceKernelHelpers.java b/hostsidetests/tagging/common/src/android/cts/tagging/support/DeviceKernelHelpers.java
index 2453192..bb956bd 100644
--- a/hostsidetests/tagging/common/src/android/cts/tagging/support/DeviceKernelHelpers.java
+++ b/hostsidetests/tagging/common/src/android/cts/tagging/support/DeviceKernelHelpers.java
@@ -16,18 +16,20 @@
package android.cts.tagging.support;
-import android.app.Activity;
import android.cts.tagging.Utils;
-import android.os.Bundle;
import android.util.Log;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
-public class DeviceKernelHelpers extends Activity {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DeviceKernelHelpers {
private static final String TAG = DeviceKernelHelpers.class.getSimpleName();
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
+ @Test
+ public void logKernelTaggedAddressABISupport() {
if (Utils.kernelSupportsTaggedPointers()) {
Log.i(TAG, "Kernel supports tagged pointers: true");
} else {
diff --git a/hostsidetests/tagging/sdk_30/AndroidManifest.xml b/hostsidetests/tagging/sdk_30/AndroidManifest.xml
index cc1c6c4..e381988 100644
--- a/hostsidetests/tagging/sdk_30/AndroidManifest.xml
+++ b/hostsidetests/tagging/sdk_30/AndroidManifest.xml
@@ -30,11 +30,21 @@
<process android:process=":CrashMemtagAsync"
android:memtagMode="async" />
<process android:process=":CrashProcess" />
+ <process android:process=":HeapZeroInitProcess"
+ android:nativeHeapZeroInitialized="true" />
+ <process android:process=":HeapZeroInitMemtagAsyncProcess"
+ android:memtagMode="async"
+ android:nativeHeapZeroInitialized="true" />
</processes>
+ <activity android:name=".TestActivity" />
+
<activity android:name=".CrashActivity" android:process=":CrashProcess" />
<activity android:name=".CrashMemtagSyncActivity" android:process=":CrashMemtagSync" />
<activity android:name=".CrashMemtagAsyncActivity" android:process=":CrashMemtagAsync" />
+ <activity android:name=".HeapZeroInitActivity" android:process=":HeapZeroInitProcess" />
+ <activity android:name=".HeapZeroInitMemtagAsyncActivity"
+ android:process=":HeapZeroInitMemtagAsyncProcess" />
</application>
<instrumentation
diff --git a/hostsidetests/tagging/sdk_30/src/android/cts/tagging/sdk30/HeapZeroInitActivity.java b/hostsidetests/tagging/sdk_30/src/android/cts/tagging/sdk30/HeapZeroInitActivity.java
new file mode 100644
index 0000000..0ae44a8
--- /dev/null
+++ b/hostsidetests/tagging/sdk_30/src/android/cts/tagging/sdk30/HeapZeroInitActivity.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.cts.tagging.sdk30;
+
+import android.app.Activity;
+import android.cts.tagging.Utils;
+import android.os.Bundle;
+import android.util.Log;
+
+public class HeapZeroInitActivity extends Activity {
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+ boolean result = Utils.heapIsZeroInitialized();
+ setResult(RESULT_FIRST_USER + (result ? 1 : 0));
+ finish();
+ }
+}
diff --git a/hostsidetests/tagging/sdk_30/src/android/cts/tagging/sdk30/HeapZeroInitMemtagAsyncActivity.java b/hostsidetests/tagging/sdk_30/src/android/cts/tagging/sdk30/HeapZeroInitMemtagAsyncActivity.java
new file mode 100644
index 0000000..053681a
--- /dev/null
+++ b/hostsidetests/tagging/sdk_30/src/android/cts/tagging/sdk30/HeapZeroInitMemtagAsyncActivity.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.cts.tagging.sdk30;
+
+import android.app.Activity;
+import android.cts.tagging.Utils;
+import android.os.Bundle;
+import android.util.Log;
+
+public class HeapZeroInitMemtagAsyncActivity extends Activity {
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+ boolean result = Utils.heapIsZeroInitialized();
+ setResult(RESULT_FIRST_USER + (result ? 1 : 0));
+ finish();
+ }
+}
diff --git a/hostsidetests/tagging/sdk_30/src/android/cts/tagging/sdk30/TaggingTest.java b/hostsidetests/tagging/sdk_30/src/android/cts/tagging/sdk30/TaggingTest.java
index 6261de1..cc5bf02 100644
--- a/hostsidetests/tagging/sdk_30/src/android/cts/tagging/sdk30/TaggingTest.java
+++ b/hostsidetests/tagging/sdk_30/src/android/cts/tagging/sdk30/TaggingTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import android.app.Instrumentation.ActivityResult;
import android.content.Context;
import android.content.Intent;
import android.cts.tagging.Utils;
@@ -28,10 +29,12 @@
import androidx.test.filters.SmallTest;
import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.runner.RunWith;
+import org.junit.Rule;
import org.junit.Test;
import com.android.compatibility.common.util.DropBoxReceiver;
@@ -73,6 +76,7 @@
mContext.startActivity(intent);
assertTrue(receiver.await());
+ assertTrue(Utils.mistaggedKernelUaccessFails());
}
@Test
@@ -90,7 +94,7 @@
mContext.startActivity(intent);
assertTrue(receiver.await());
- assertTrue(Utils.mistaggedKernelUaccessFails());
+ assertFalse(Utils.mistaggedKernelUaccessFails());
}
@Test
@@ -132,4 +136,23 @@
assertTrue(receiver.await());
}
+
+ @Rule
+ public ActivityTestRule<TestActivity> mTestActivityRule =
+ new ActivityTestRule<>(
+ TestActivity.class, false /*initialTouchMode*/, true /*launchActivity*/);
+
+ @Test
+ public void testHeapZeroInitActivity() throws Exception {
+ TestActivity activity = mTestActivityRule.getActivity();
+ boolean result = activity.callActivity(HeapZeroInitActivity.class);
+ assertTrue(result);
+ }
+
+ @Test
+ public void testHeapZeroInitMemtagAsyncActivity() throws Exception {
+ TestActivity activity = mTestActivityRule.getActivity();
+ boolean result = activity.callActivity(HeapZeroInitMemtagAsyncActivity.class);
+ assertTrue(result);
+ }
}
diff --git a/hostsidetests/tagging/sdk_30/src/android/cts/tagging/sdk30/TestActivity.java b/hostsidetests/tagging/sdk_30/src/android/cts/tagging/sdk30/TestActivity.java
new file mode 100644
index 0000000..ec099af
--- /dev/null
+++ b/hostsidetests/tagging/sdk_30/src/android/cts/tagging/sdk30/TestActivity.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.cts.tagging.sdk30;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+import java.lang.Override;
+
+
+public class TestActivity extends Activity {
+ static final String TAG = "TestActivity";
+
+ private int mResult;
+ private final Object mFinishEvent = new Object();
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ mResult = resultCode;
+ synchronized (mFinishEvent) {
+ mFinishEvent.notify();
+ }
+ }
+
+ public boolean callActivity(Class<?> cls) throws Exception {
+ Thread thread = new Thread() {
+ @Override
+ public void run() {
+ try {
+ Context context = getApplicationContext();
+ Intent intent = new Intent(context, cls);
+ startActivityForResult(intent, 0);
+
+ synchronized (mFinishEvent) {
+ mFinishEvent.wait();
+ }
+ } catch(Exception e) {
+ Log.d(TAG, "callActivity got an exception " + e.toString());
+ }
+ }
+ };
+ thread.start();
+ thread.join(50000 /* millis */);
+
+ if (mResult == RESULT_OK) {
+ throw new Exception();
+ }
+ return (mResult - RESULT_FIRST_USER) == 1;
+ }
+}
diff --git a/hostsidetests/tagging/src/com/android/cts/tagging/TaggingBaseTest.java b/hostsidetests/tagging/src/com/android/cts/tagging/TaggingBaseTest.java
index 30d6841..6fa5cd9 100644
--- a/hostsidetests/tagging/src/com/android/cts/tagging/TaggingBaseTest.java
+++ b/hostsidetests/tagging/src/com/android/cts/tagging/TaggingBaseTest.java
@@ -25,9 +25,9 @@
private static final String DEVICE_KERNEL_HELPER_CLASS_NAME = "DeviceKernelHelpers";
private static final String DEVICE_KERNEL_HELPER_APK_NAME = "DeviceKernelHelpers.apk";
private static final String DEVICE_KERNEL_HELPER_PKG_NAME = "android.cts.tagging.support";
- private static final String KERNEL_HELPER_START_COMMAND =
- String.format("am start -W -a android.intent.action.MAIN -n %s/.%s",
- DEVICE_KERNEL_HELPER_PKG_NAME, DEVICE_KERNEL_HELPER_CLASS_NAME);
+ private static final String KERNEL_HELPER_START_COMMAND = String.format(
+ "am instrument -w -e package %1$s %1$s/androidx.test.runner.AndroidJUnitRunner",
+ DEVICE_KERNEL_HELPER_PKG_NAME);
protected static final long NATIVE_HEAP_POINTER_TAGGING_CHANGE_ID = 135754954;
protected static final String DEVICE_TEST_CLASS_NAME = ".TaggingTest";
diff --git a/hostsidetests/tagging/src/com/android/cts/tagging/TaggingSdk30Test.java b/hostsidetests/tagging/src/com/android/cts/tagging/TaggingSdk30Test.java
index c43a015..b6510d7 100644
--- a/hostsidetests/tagging/src/com/android/cts/tagging/TaggingSdk30Test.java
+++ b/hostsidetests/tagging/src/com/android/cts/tagging/TaggingSdk30Test.java
@@ -144,4 +144,16 @@
/*enabledChanges*/ ImmutableSet.of(),
/*disabledChanges*/ ImmutableSet.of());
}
+
+ public void testHeapZeroInitActivity() throws Exception {
+ runDeviceCompatTest(TEST_PKG, ".TaggingTest", "testHeapZeroInitActivity",
+ /*enabledChanges*/ ImmutableSet.of(),
+ /*disabledChanges*/ ImmutableSet.of());
+ }
+
+ public void testHeapZeroInitMemtagAsyncActivity() throws Exception {
+ runDeviceCompatTest(TEST_PKG, ".TaggingTest", "testHeapZeroInitMemtagAsyncActivity",
+ /*enabledChanges*/ ImmutableSet.of(),
+ /*disabledChanges*/ ImmutableSet.of());
+ }
}
diff --git a/hostsidetests/theme/README b/hostsidetests/theme/README
index 4bf32cd..9ecbe7d 100644
--- a/hostsidetests/theme/README
+++ b/hostsidetests/theme/README
@@ -47,7 +47,7 @@
4. From the console, set up your build environment for x86_64 and build CTS:
- lunch sdk_x86_64-eng && make cts -j32
+ source build/envsetup.sh && lunch sdk_x86_64-eng && make cts -j32
5. Use the reference image script to generate the reference images. The script
will automatically start the emulator in the required configurations and
diff --git a/hostsidetests/theme/app/src/android/theme/app/AssetBucketVerifier.java b/hostsidetests/theme/app/src/android/theme/app/AssetBucketVerifier.java
deleted file mode 100644
index 09875b1..0000000
--- a/hostsidetests/theme/app/src/android/theme/app/AssetBucketVerifier.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.theme.app;
-
-import android.content.Context;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-class AssetBucketVerifier {
- /** Asset file to verify. */
- private static final String ASSET_NAME = "ic_star_black_16dp.png";
-
- /** Densities at which {@link #ASSET_NAME} may be defined. */
- private static final int[] DENSITIES_DPI = new int[] {
- 160, // mdpi
- 240, // hdpi
- 320, // xhdpi
- 480, // xxhdpi
- 640, // xxxhdpi
- };
-
- /** Bucket names corresponding to {@link #DENSITIES_DPI} entries. */
- private static final String[] DENSITIES_NAME = new String[] {
- "mdpi",
- "hdpi",
- "xhdpi",
- "xxhdpi",
- "xxxhdpi"
- };
-
- static class Result {
- String expectedAtDensity;
- List<String> foundAtDensity;
- }
-
- static Result verifyAssetBucket(Context context) {
- List<String> foundAtDensity = new ArrayList<>();
- String expectedAtDensity = null;
-
- int deviceDensityDpi = context.getResources().getConfiguration().densityDpi;
- for (int i = 0; i < DENSITIES_DPI.length; i++) {
- // Find the matching or next-highest density bucket.
- if (expectedAtDensity == null && DENSITIES_DPI[i] >= deviceDensityDpi) {
- expectedAtDensity = DENSITIES_NAME[i];
- }
-
- // Try to load and close the asset from the current density.
- try {
- context.getAssets().openNonAssetFd(1,
- "res/drawable-" + DENSITIES_NAME[i] + "-v4/" + ASSET_NAME).close();
- foundAtDensity.add(DENSITIES_NAME[i]);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- if (expectedAtDensity == null) {
- expectedAtDensity = DENSITIES_NAME[DENSITIES_NAME.length - 1];
- }
-
- Result result = new Result();
- result.expectedAtDensity = expectedAtDensity;
- result.foundAtDensity = foundAtDensity;
- return result;
- }
-}
diff --git a/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java b/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java
index 6be679b..b764752 100644
--- a/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java
+++ b/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java
@@ -65,41 +65,14 @@
// Useful for local testing. Not required for CTS harness.
getWindow().addFlags(LayoutParams.FLAG_KEEP_SCREEN_ON);
- // Make sure the device has reasonable assets.
- String assetDensityFailureMsg = checkAssetDensity();
- if (assetDensityFailureMsg != null) {
- finish("Failed to verify device assets: "+ assetDensityFailureMsg, false);
+ mOutputDir = setupOutputDirectory();
+ if (mOutputDir == null) {
+ finish("Failed to create output directory " + mOutputDir.getAbsolutePath(), false);
} else {
- mOutputDir = setupOutputDirectory();
- if (mOutputDir == null) {
- finish("Failed to create output directory: " + OUT_DIR, false);
- } else {
- generateNextImage();
- }
+ generateNextImage();
}
}
- private String checkAssetDensity() {
- AssetBucketVerifier.Result result = AssetBucketVerifier.verifyAssetBucket(this);
-
- String message;
- if (result.foundAtDensity.contains(result.expectedAtDensity)) {
- message = null;
- } else if (result.foundAtDensity.isEmpty()) {
- message = "Failed to find expected device assets at any density";
- } else {
- StringBuilder foundAtDensityStr = new StringBuilder(result.foundAtDensity.get(0));
- for (int i = 1; i < result.foundAtDensity.size(); i++) {
- foundAtDensityStr.append(", ");
- foundAtDensityStr.append(result.foundAtDensity.get(i));
- }
- message = "Failed to find device assets at expected density ("
- + result.expectedAtDensity + "), but found at " + foundAtDensityStr;
- }
-
- return message;
- }
-
private File setupOutputDirectory() {
mOutputDir = new File(Environment.getExternalStorageDirectory(), OUT_DIR);
ThemeTestUtils.deleteDirectory(mOutputDir);
@@ -132,9 +105,8 @@
private void generateNextImage() {
// Keep trying themes until one works.
boolean success = false;
- while (mCurrentTheme < THEMES.length && !success) {
+ while (++mCurrentTheme < THEMES.length && !success) {
success = launchThemeDeviceActivity();
- mCurrentTheme++;
}
// If we ran out of themes, we're done.
diff --git a/hostsidetests/theme/assets/30/600dpi.zip b/hostsidetests/theme/assets/30/600dpi.zip
new file mode 100644
index 0000000..b9a13aa4
--- /dev/null
+++ b/hostsidetests/theme/assets/30/600dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/140dpi.zip b/hostsidetests/theme/assets/T/140dpi.zip
new file mode 100644
index 0000000..48de32b
--- /dev/null
+++ b/hostsidetests/theme/assets/T/140dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/180dpi.zip b/hostsidetests/theme/assets/T/180dpi.zip
new file mode 100644
index 0000000..4def986
--- /dev/null
+++ b/hostsidetests/theme/assets/T/180dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/200dpi.zip b/hostsidetests/theme/assets/T/200dpi.zip
new file mode 100644
index 0000000..fe2495e
--- /dev/null
+++ b/hostsidetests/theme/assets/T/200dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/220dpi.zip b/hostsidetests/theme/assets/T/220dpi.zip
new file mode 100644
index 0000000..a2c2ea2
--- /dev/null
+++ b/hostsidetests/theme/assets/T/220dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/260dpi.zip b/hostsidetests/theme/assets/T/260dpi.zip
new file mode 100644
index 0000000..74890a2
--- /dev/null
+++ b/hostsidetests/theme/assets/T/260dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/280dpi.zip b/hostsidetests/theme/assets/T/280dpi.zip
new file mode 100644
index 0000000..83fd290
--- /dev/null
+++ b/hostsidetests/theme/assets/T/280dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/300dpi.zip b/hostsidetests/theme/assets/T/300dpi.zip
new file mode 100644
index 0000000..25334d8
--- /dev/null
+++ b/hostsidetests/theme/assets/T/300dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/340dpi.zip b/hostsidetests/theme/assets/T/340dpi.zip
new file mode 100644
index 0000000..2092326
--- /dev/null
+++ b/hostsidetests/theme/assets/T/340dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/360dpi.zip b/hostsidetests/theme/assets/T/360dpi.zip
new file mode 100644
index 0000000..c13ad5c
--- /dev/null
+++ b/hostsidetests/theme/assets/T/360dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/400dpi.zip b/hostsidetests/theme/assets/T/400dpi.zip
new file mode 100644
index 0000000..1df1a95
--- /dev/null
+++ b/hostsidetests/theme/assets/T/400dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/420dpi.zip b/hostsidetests/theme/assets/T/420dpi.zip
new file mode 100644
index 0000000..d58d418
--- /dev/null
+++ b/hostsidetests/theme/assets/T/420dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/440dpi.zip b/hostsidetests/theme/assets/T/440dpi.zip
new file mode 100644
index 0000000..535102f
--- /dev/null
+++ b/hostsidetests/theme/assets/T/440dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/560dpi.zip b/hostsidetests/theme/assets/T/560dpi.zip
new file mode 100644
index 0000000..20f1c7b
--- /dev/null
+++ b/hostsidetests/theme/assets/T/560dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/hdpi.zip b/hostsidetests/theme/assets/T/hdpi.zip
new file mode 100644
index 0000000..582989d
--- /dev/null
+++ b/hostsidetests/theme/assets/T/hdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/ldpi.zip b/hostsidetests/theme/assets/T/ldpi.zip
new file mode 100644
index 0000000..3035146
--- /dev/null
+++ b/hostsidetests/theme/assets/T/ldpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/mdpi.zip b/hostsidetests/theme/assets/T/mdpi.zip
new file mode 100644
index 0000000..a831e7b
--- /dev/null
+++ b/hostsidetests/theme/assets/T/mdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/tvdpi.zip b/hostsidetests/theme/assets/T/tvdpi.zip
new file mode 100644
index 0000000..bd4bf75
--- /dev/null
+++ b/hostsidetests/theme/assets/T/tvdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/xhdpi.zip b/hostsidetests/theme/assets/T/xhdpi.zip
new file mode 100644
index 0000000..0dd72e2
--- /dev/null
+++ b/hostsidetests/theme/assets/T/xhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/xxhdpi.zip b/hostsidetests/theme/assets/T/xxhdpi.zip
new file mode 100644
index 0000000..64fc846
--- /dev/null
+++ b/hostsidetests/theme/assets/T/xxhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/assets/T/xxxhdpi.zip b/hostsidetests/theme/assets/T/xxxhdpi.zip
new file mode 100644
index 0000000..87beb9a
--- /dev/null
+++ b/hostsidetests/theme/assets/T/xxxhdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/generate_images.py b/hostsidetests/theme/generate_images.py
index 4c812b2..0b0d6d8 100755
--- a/hostsidetests/theme/generate_images.py
+++ b/hostsidetests/theme/generate_images.py
@@ -27,7 +27,10 @@
from queue import Queue, Empty
-# This dict should contain one entry for every density listed in CDD 7.1.1.3.
+# This dict should contain one entry for every density listed in DisplayMetrics.
+# See CDD 7.1.1.3 for more information on densities at which CTS can run. If you
+# are only generating reference images for a single density, you can comment out
+# the other densities and then run the script.
CTS_THEME_dict = {
120: "ldpi",
140: "140dpi",
@@ -49,6 +52,7 @@
450: "450dpi",
480: "xxhdpi",
560: "560dpi",
+ 600: "600dpi",
640: "xxxhdpi",
}
diff --git a/hostsidetests/ui/Android.bp b/hostsidetests/ui/Android.bp
new file mode 100644
index 0000000..6490706
--- /dev/null
+++ b/hostsidetests/ui/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_test_host {
+ name: "CtsUiHostTestCases",
+ defaults: ["cts_defaults"],
+ srcs: ["src/**/*.java"],
+ libs: [
+ "cts-tradefed",
+ "tradefed",
+ "compatibility-host-util",
+ ],
+
+ // *Not* tagged as a cts test artifact intentionally: b/109660132
+ //$(COMPATIBILITY_TESTCASES_OUT_cts)/CtsUiHostTestCases.jar : $(COMPATIBILITY_TESTCASES_OUT_cts)/com.replica.replicaisland.apk
+ test_suites: ["general-tests"],
+}
diff --git a/hostsidetests/ui/Android.mk b/hostsidetests/ui/Android.mk
deleted file mode 100644
index 096c33d..0000000
--- a/hostsidetests/ui/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (C) 2012 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := CtsUiHostTestCases
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
-
-# *Not* tagged as a cts test artifact intentionally: b/109660132
-#$(COMPATIBILITY_TESTCASES_OUT_cts)/CtsUiHostTestCases.jar : $(COMPATIBILITY_TESTCASES_OUT_cts)/com.replica.replicaisland.apk
-LOCAL_COMPATIBILITY_SUITE := general-tests
-
-include $(BUILD_CTS_HOST_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libs/deviceutillegacy/src/android/webkit/cts/OWNERS b/libs/deviceutillegacy/src/android/webkit/cts/OWNERS
new file mode 100644
index 0000000..a30553b
--- /dev/null
+++ b/libs/deviceutillegacy/src/android/webkit/cts/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 76427
+file:/tests/tests/webkit/OWNERS
diff --git a/libs/install/Android.bp b/libs/install/Android.bp
index 5b492a2..284f2fe 100644
--- a/libs/install/Android.bp
+++ b/libs/install/Android.bp
@@ -126,6 +126,7 @@
static_libs: [
"cts-install-lib-java",
],
+ min_sdk_version: "30",
}
java_library_host {
diff --git a/suite/audio_quality/client/Android.mk b/suite/audio_quality/client/Android.mk
index 6d60541..edef96b 100644
--- a/suite/audio_quality/client/Android.mk
+++ b/suite/audio_quality/client/Android.mk
@@ -24,6 +24,8 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsAudioClient
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_PROGUARD_FLAG_FILES := proguard.cfg
diff --git a/tests/BlobStore/OWNERS b/tests/BlobStore/OWNERS
index bf870975..3a47c48 100644
--- a/tests/BlobStore/OWNERS
+++ b/tests/BlobStore/OWNERS
@@ -1,2 +1,2 @@
-# Bug component: 95221
+# Bug component: 533114
include platform/frameworks/base:/apex/blobstore/OWNERS
diff --git a/tests/DropBoxManager/src/android/dropboxmanager/cts/DropBoxTests.java b/tests/DropBoxManager/src/android/dropboxmanager/cts/DropBoxTests.java
index 3b6c7da..879286f 100644
--- a/tests/DropBoxManager/src/android/dropboxmanager/cts/DropBoxTests.java
+++ b/tests/DropBoxManager/src/android/dropboxmanager/cts/DropBoxTests.java
@@ -133,12 +133,18 @@
restoreDropboxDefaults();
}
- private void sendExcessiveDropBoxEntries(String tag, int count, long delayPerEntry)
+ private void sendExcessiveDropBoxEntries(String tag, int count, long interval)
throws Exception {
+ // addText() can take dozens of milliseconds. In order to ensure addText is called at the
+ // given interval, we keep track of the timestamp when the next addText call should occur.
+ long nextTime = SystemClock.elapsedRealtime();
int i = 0;
mDropBoxManager.addText(tag, String.valueOf(i++));
for (; i < count; i++) {
- Thread.sleep(delayPerEntry);
+ nextTime += interval;
+ // Sleep until when we should send the next entry.
+ final long delay = nextTime - SystemClock.elapsedRealtime();
+ if (delay > 0) Thread.sleep(delay);
mDropBoxManager.addText(tag, String.valueOf(i));
}
}
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
index faeb8f96..8bed13d 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
@@ -15,12 +15,15 @@
*/
package android.jobscheduler.cts;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
import android.annotation.TargetApi;
import android.app.job.JobInfo;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
-import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
@@ -490,9 +493,11 @@
static void setWifiState(final boolean enable,
final ConnectivityManager cm, final WifiManager wm) throws InterruptedException {
if (enable != isWiFiConnected(cm, wm)) {
- NetworkRequest nr = new NetworkRequest.Builder().addCapability(
- NetworkCapabilities.NET_CAPABILITY_NOT_METERED).build();
- NetworkTracker tracker = new NetworkTracker(false, enable, cm);
+ NetworkRequest nr = new NetworkRequest.Builder().clearCapabilities().build();
+ NetworkCapabilities nc = new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_WIFI)
+ .build();
+ NetworkTracker tracker = new NetworkTracker(nc, enable, cm);
cm.registerNetworkCallback(nr, tracker);
if (enable) {
@@ -515,7 +520,16 @@
}
private static boolean isWiFiConnected(final ConnectivityManager cm, final WifiManager wm) {
- return wm.isWifiEnabled() && cm.getActiveNetwork() != null && !cm.isActiveNetworkMetered();
+ if (!wm.isWifiEnabled()) {
+ return false;
+ }
+ final Network network = cm.getActiveNetwork();
+ if (network == null) {
+ return false;
+ }
+ final NetworkCapabilities networkCapabilities = cm.getNetworkCapabilities(network);
+ return networkCapabilities != null && networkCapabilities.hasTransport(TRANSPORT_WIFI)
+ && networkCapabilities.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
}
/**
@@ -528,8 +542,11 @@
*/
private void disconnectWifiToConnectToMobile() throws InterruptedException {
if (mHasWifi && mWifiManager.isWifiEnabled()) {
- NetworkRequest nr = new NetworkRequest.Builder().build();
- NetworkTracker tracker = new NetworkTracker(true, true, mCm);
+ NetworkRequest nr = new NetworkRequest.Builder().clearCapabilities().build();
+ NetworkCapabilities nc = new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .build();
+ NetworkTracker tracker = new NetworkTracker(nc, true, mCm);
mCm.registerNetworkCallback(nr, tracker);
disconnectFromWifi();
@@ -556,7 +573,7 @@
private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
- private final boolean mNetworkMetered;
+ private final NetworkCapabilities mExpectedCapabilities;
private final boolean mExpectedConnected;
@@ -569,16 +586,15 @@
}
};
- private NetworkTracker(boolean networkMetered, boolean expectedConnected,
+ private NetworkTracker(NetworkCapabilities expectedCapabilities, boolean expectedConnected,
ConnectivityManager cm) {
- mNetworkMetered = networkMetered;
+ mExpectedCapabilities = expectedCapabilities;
mExpectedConnected = expectedConnected;
mCm = cm;
}
@Override
- public void onAvailable(Network network, NetworkCapabilities networkCapabilities,
- LinkProperties linkProperties, boolean blocked) {
+ public void onAvailable(Network network) {
// Available doesn't mean it's the active network. We need to check that separately.
checkActiveNetwork();
}
@@ -594,20 +610,23 @@
}
private void checkActiveNetwork() {
+ mHandler.removeMessages(MSG_CHECK_ACTIVE_NETWORK);
if (mReceiveLatch.getCount() == 0) {
return;
}
+ Network activeNetwork = mCm.getActiveNetwork();
if (mExpectedConnected) {
- if (mCm.getActiveNetwork() != null
- && mNetworkMetered == mCm.isActiveNetworkMetered()) {
+ if (activeNetwork != null && mExpectedCapabilities.satisfiedByNetworkCapabilities(
+ mCm.getNetworkCapabilities(activeNetwork))) {
mReceiveLatch.countDown();
} else {
mHandler.sendEmptyMessageDelayed(MSG_CHECK_ACTIVE_NETWORK, 5000);
}
} else {
- if (mCm.getActiveNetwork() != null
- && mNetworkMetered != mCm.isActiveNetworkMetered()) {
+ if (activeNetwork != null
+ || !mExpectedCapabilities.satisfiedByNetworkCapabilities(
+ mCm.getNetworkCapabilities(activeNetwork))) {
mReceiveLatch.countDown();
} else {
mHandler.sendEmptyMessageDelayed(MSG_CHECK_ACTIVE_NETWORK, 5000);
diff --git a/tests/accessibilityservice/res/values/strings.xml b/tests/accessibilityservice/res/values/strings.xml
index 7b6be1e..4dfe78b 100644
--- a/tests/accessibilityservice/res/values/strings.xml
+++ b/tests/accessibilityservice/res/values/strings.xml
@@ -32,7 +32,7 @@
<string name="text_input_blah_blah">Blah blah</string>
<!-- String title of the button -->
- <string name="button_title">Click me</string>
+ <string name="button_title">Click</string>
<string name="button_tooltip">Never press this button</string>
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
index 37a4997..d57794a 100755
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
@@ -69,7 +69,7 @@
public class AccessibilityGestureDetectorTest {
// Constants
- private static final float GESTURE_LENGTH_INCHES = 1.0f;
+ private static final float GESTURE_LENGTH_INCHES = 2.0f;
// The movement should exceed the threshold 1 cm in 150 ms defined in Swipe.java. It means the
// swipe velocity in testing should be greater than 2.54 cm / 381 ms. Therefore the
// duration should be smaller than 381.
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java
index b0f3570..3ceab31 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/TouchExplorerTest.java
@@ -153,7 +153,11 @@
mView.getLocationOnScreen(viewLocation);
mTapLocation = new PointF(viewLocation[0] + midX, viewLocation[1] + midY);
mSwipeDistance = mView.getWidth() / 4;
- mSwipeTimeMillis = (long) mSwipeDistance * 4;
+
+ // This must be slower than 10mm per 150ms to be detected as touch exploration.
+ final double swipeDistanceMm = mSwipeDistance / metrics.xdpi * 25.4;
+ mSwipeTimeMillis = (long) swipeDistanceMm * 20;
+
mView.setOnClickListener(mClickListener);
mView.setOnLongClickListener(mLongClickListener);
});
diff --git a/tests/app/Android.bp b/tests/app/Android.bp
index bc5125a..d66376a 100644
--- a/tests/app/Android.bp
+++ b/tests/app/Android.bp
@@ -83,6 +83,9 @@
min_sdk_version: "14",
manifest: "DownloadManagerApi28Test/AndroidManifest.xml",
test_config: "DownloadManagerApi28Test/AndroidTest.xml",
+ lint: {
+ baseline_filename: "lint-baseline-api-28.xml",
+ },
}
android_test {
@@ -117,6 +120,9 @@
min_sdk_version: "14",
manifest: "DownloadManagerInstallerTest/AndroidManifest.xml",
test_config: "DownloadManagerInstallerTest/AndroidTest.xml",
+ lint: {
+ baseline_filename: "lint-baseline-installer.xml",
+ },
}
android_test {
diff --git a/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java b/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java
index 77973bb..db74563 100644
--- a/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java
+++ b/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java
@@ -825,6 +825,11 @@
// Start a process and crash it
startService(ACTION_NATIVE_CRASH, STUB_SERVICE_NAME, true, false);
+ // Native crashes are handled asynchronously from the actual crash, so
+ // it's possible for us to notice that the process crashed before an
+ // actual tombstone exists.
+ Thread.sleep(1000);
+
long now2 = System.currentTimeMillis();
List<ApplicationExitInfo> list = ShellIdentityUtils.invokeMethodWithShellPermissions(
STUB_PACKAGE_NAME, mStubPackagePid, 1,
diff --git a/tests/app/lint-baseline-api-28.xml b/tests/app/lint-baseline-api-28.xml
new file mode 100644
index 0000000..57e7aee
--- /dev/null
+++ b/tests/app/lint-baseline-api-28.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
+
+ <issue
+ id="NewApi"
+ message="`@android:style/Theme.Material.Dialog` requires API level 21 (current min is 14)"
+ errorLine1=" <style name="DialogTheme_Test" parent="@android:style/Theme.Material.Dialog">"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="cts/tests/app/app/res/values/styles.xml"
+ line="168"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="View requires API level 21 (current min is 14): `<Toolbar>`"
+ errorLine1="<Toolbar android:id="@+id/toolbar""
+ errorLine2=" ~~~~~~~">
+ <location
+ file="cts/tests/app/app/res/layout/toolbar_activity.xml"
+ line="23"
+ column="2"/>
+ </issue>
+
+</issues>
diff --git a/tests/app/lint-baseline-installer.xml b/tests/app/lint-baseline-installer.xml
new file mode 100644
index 0000000..57e7aee
--- /dev/null
+++ b/tests/app/lint-baseline-installer.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
+
+ <issue
+ id="NewApi"
+ message="`@android:style/Theme.Material.Dialog` requires API level 21 (current min is 14)"
+ errorLine1=" <style name="DialogTheme_Test" parent="@android:style/Theme.Material.Dialog">"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="cts/tests/app/app/res/values/styles.xml"
+ line="168"
+ column="36"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="View requires API level 21 (current min is 14): `<Toolbar>`"
+ errorLine1="<Toolbar android:id="@+id/toolbar""
+ errorLine2=" ~~~~~~~">
+ <location
+ file="cts/tests/app/app/res/layout/toolbar_activity.xml"
+ line="23"
+ column="2"/>
+ </issue>
+
+</issues>
diff --git a/tests/app/lint-baseline.xml b/tests/app/lint-baseline.xml
new file mode 100644
index 0000000..9bd7004
--- /dev/null
+++ b/tests/app/lint-baseline.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
+
+ <issue
+ id="NewApi"
+ message="`<vector>` requires API level 21 (current min is 14) or building with Android Gradle plugin 1.4 or higher"
+ errorLine1="<vector xmlns:android="http://schemas.android.com/apk/res/android""
+ errorLine2=" ~~~~~~">
+ <location
+ file="cts/tests/app/res/drawable/ic_android.xml"
+ line="17"
+ column="2"/>
+ </issue>
+
+</issues>
diff --git a/tests/app/src/android/app/cts/SystemFeaturesTest.java b/tests/app/src/android/app/cts/SystemFeaturesTest.java
index 03012c8..19dc7a3 100644
--- a/tests/app/src/android/app/cts/SystemFeaturesTest.java
+++ b/tests/app/src/android/app/cts/SystemFeaturesTest.java
@@ -644,7 +644,7 @@
}
private boolean isAndroidEmulator() {
- return PropertyUtil.propertyEquals("ro.kernel.qemu", "1");
+ return PropertyUtil.propertyEquals("ro.boot.qemu", "1");
}
private void assertFeature(boolean exist, String feature) {
diff --git a/tests/app/src/android/app/cts/UserHandleTest.java b/tests/app/src/android/app/cts/UserHandleTest.java
index 4f4b829..ec7cc40 100644
--- a/tests/app/src/android/app/cts/UserHandleTest.java
+++ b/tests/app/src/android/app/cts/UserHandleTest.java
@@ -60,15 +60,15 @@
public void testGetUid() {
assertEquals(
UserHandle.getUid(UserHandle.USER_ALL, TEST_APP_ID),
- UserHandle.getUid(UserHandle.ALL, TEST_APP_ID));
+ UserHandle.ALL.getUid(TEST_APP_ID));
assertEquals(
UserHandle.getUid(UserHandle.USER_SYSTEM, TEST_APP_ID),
- UserHandle.getUid(UserHandle.SYSTEM, TEST_APP_ID));
+ UserHandle.SYSTEM.getUid(TEST_APP_ID));
assertEquals(
- UserHandle.getUid(UserHandle.USER_ALL, TEST_APP_ID),
+ UserHandle.ALL.getUid(TEST_APP_ID),
UserHandle.getUid(UserHandle.ALL.getIdentifier(), TEST_APP_ID));
assertEquals(
- UserHandle.getUid(UserHandle.USER_SYSTEM, TEST_APP_ID),
+ UserHandle.SYSTEM.getUid(TEST_APP_ID),
UserHandle.getUid(UserHandle.SYSTEM.getIdentifier(), TEST_APP_ID));
}
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DisableAutofillTest.java b/tests/autofillservice/src/android/autofillservice/cts/DisableAutofillTest.java
index af2837b..65f3697 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DisableAutofillTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DisableAutofillTest.java
@@ -120,7 +120,7 @@
// Asserts isEnabled() status.
assertAutofillEnabled(activity, action == PostLaunchAction.ASSERT_ENABLED_AND_AUTOFILL);
} finally {
- activity.finish();
+ mUiBot.waitForWindowChange(() -> activity.finish());
}
return SystemClock.elapsedRealtime() - before;
}
diff --git a/tests/bugreport/src/android/bugreport/cts/BugreportManagerTest.java b/tests/bugreport/src/android/bugreport/cts/BugreportManagerTest.java
index bea0dd1..975b08c 100644
--- a/tests/bugreport/src/android/bugreport/cts/BugreportManagerTest.java
+++ b/tests/bugreport/src/android/bugreport/cts/BugreportManagerTest.java
@@ -76,6 +76,7 @@
assertThat(bp.getMode()).isEqualTo(expected_mode);
}
+ @LargeTest
@Test
public void testTelephonyBugreport() throws Exception {
Pair<String, String> brFiles = triggerBugreport(BugreportParams.BUGREPORT_MODE_TELEPHONY);
diff --git a/tests/camera/Android.mk b/tests/camera/Android.mk
index 749fed5..f2bf9fc 100644
--- a/tests/camera/Android.mk
+++ b/tests/camera/Android.mk
@@ -46,6 +46,8 @@
LOCAL_COMPATIBILITY_SUITE := cts general-tests
LOCAL_PACKAGE_NAME := CtsCameraTestCases
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_SDK_VERSION := test_current
diff --git a/tests/camera/api25test/Android.mk b/tests/camera/api25test/Android.mk
index c00b2d5..eaa99aa 100644
--- a/tests/camera/api25test/Android.mk
+++ b/tests/camera/api25test/Android.mk
@@ -32,6 +32,8 @@
CtsCameraUtils
LOCAL_PACKAGE_NAME := CtsCameraApi25TestCases
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_SDK_VERSION := 25
diff --git a/tests/camera/libctscamera2jni/native-camera-jni.cpp b/tests/camera/libctscamera2jni/native-camera-jni.cpp
index f853468..a97ac9b 100644
--- a/tests/camera/libctscamera2jni/native-camera-jni.cpp
+++ b/tests/camera/libctscamera2jni/native-camera-jni.cpp
@@ -314,6 +314,7 @@
~CaptureResultListener() {
std::unique_lock<std::mutex> l(mMutex);
clearSavedRequestsLocked();
+ mCompletedFrameNumbers.clear();
clearFailedLostFrameNumbersLocked();
}
@@ -361,7 +362,7 @@
thiz->mCompletedRequests.push_back(ACaptureRequest_copy(request));
}
- thiz->mLastCompletedFrameNumber = entry.data.i64[0];
+ thiz->mCompletedFrameNumbers.insert(entry.data.i64[0]);
thiz->mResultCondition.notify_one();
}
@@ -439,7 +440,7 @@
thiz->mCompletedRequests.push_back(ACaptureRequest_copy(request));
}
- thiz->mLastCompletedFrameNumber = entry.data.i64[0];
+ thiz->mCompletedFrameNumbers.insert(entry.data.i64[0]);
thiz->mResultCondition.notify_one();
}
@@ -523,7 +524,7 @@
bool ret = false;
std::unique_lock<std::mutex> l(mMutex);
- while ((mLastCompletedFrameNumber != frameNumber) &&
+ while ((mCompletedFrameNumbers.find(frameNumber) == mCompletedFrameNumbers.end()) &&
!checkForFailureOrLossLocked(frameNumber)) {
auto timeout = std::chrono::system_clock::now() +
std::chrono::seconds(timeoutSec);
@@ -532,7 +533,7 @@
}
}
- if ((mLastCompletedFrameNumber == frameNumber) ||
+ if ((mCompletedFrameNumbers.find(frameNumber) != mCompletedFrameNumbers.end()) ||
checkForFailureOrLossLocked(frameNumber)) {
ret = true;
}
@@ -571,9 +572,9 @@
std::lock_guard<std::mutex> lock(mMutex);
mLastSequenceIdCompleted = -1;
mLastSequenceFrameNumber = -1;
- mLastCompletedFrameNumber = -1;
mSaveCompletedRequests = false;
clearSavedRequestsLocked();
+ mCompletedFrameNumbers.clear();
clearFailedLostFrameNumbersLocked();
}
@@ -582,7 +583,7 @@
std::condition_variable mResultCondition;
int mLastSequenceIdCompleted = -1;
int64_t mLastSequenceFrameNumber = -1;
- int64_t mLastCompletedFrameNumber = -1;
+ std::set<int64_t> mCompletedFrameNumbers;
std::set<int64_t> mFailedFrameNumbers, mBufferLostFrameNumbers;
bool mSaveCompletedRequests = false;
std::vector<ACaptureRequest*> mCompletedRequests;
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index b9fc5a8..add4e2c 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -17,6 +17,7 @@
package android.hardware.camera2.cts;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
@@ -38,6 +39,7 @@
import android.media.CamcorderProfile;
import android.media.ImageReader;
import android.os.Build;
+import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Rational;
@@ -93,6 +95,8 @@
private static final Size HD = new Size(1280, 720);
private static final Size VGA = new Size(640, 480);
private static final Size QVGA = new Size(320, 240);
+ private static final Size UHD = new Size(3840, 2160);
+ private static final Size DC4K = new Size(4096, 2160);
private static final long MIN_BACK_SENSOR_RESOLUTION = 2000000;
private static final long MIN_FRONT_SENSOR_RESOLUTION = VGA.getHeight() * VGA.getWidth();
@@ -101,6 +105,10 @@
private static final int MAX_NUM_IMAGES = 5;
private static final long PREVIEW_RUN_MS = 500;
private static final long FRAME_DURATION_30FPS_NSEC = (long) 1e9 / 30;
+
+ private static final long MIN_BACK_SENSOR_PERFORMANCE_CLASS_RESOLUTION = 12000000;
+ private static final long MIN_FRONT_SENSOR_PERFORMANCE_CLASS_RESOLUTION = 6000000;
+
/*
* HW Levels short hand
*/
@@ -601,7 +609,14 @@
c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
Size arraySize = new Size(activeRect.width(), activeRect.height());
- Set<Size> snapshotSizeSet = snapshotConfig.getOutputSizes(ImageFormat.JPEG);
+
+ ArraySet<Size> snapshotSizeSet = new ArraySet<>(snapshotConfig.getOutputSizes(
+ ImageFormat.JPEG));
+ Set<Size> highResSnapshotSizeSet = snapshotConfig.getHighResolutionOutputSizes(
+ ImageFormat.JPEG);
+ if (highResSnapshotSizeSet != null) {
+ snapshotSizeSet.addAll(highResSnapshotSizeSet);
+ }
Size[] snapshotSizes = new Size[snapshotSizeSet.size()];
snapshotSizes = snapshotSizeSet.toArray(snapshotSizes);
Size maxJpegSize = CameraTestUtils.getMaxSize(snapshotSizes);
@@ -2423,6 +2438,146 @@
}
/**
+ * Check camera characteristics for S Performance class requirements as specified
+ * in CDD camera section 7.5
+ */
+ @Test
+ @CddTest(requirement="7.5")
+ public void testCameraSPerfClassCharacteristics() throws Exception {
+ if (mAdoptShellPerm) {
+ // Skip test for system camera. Performance class is only applicable for public camera
+ // ids.
+ return;
+ }
+ boolean isSPerfClass = CameraTestUtils.isSPerfClass();
+ if (!isSPerfClass) {
+ return;
+ }
+
+ boolean hasPrimaryRear = false;
+ boolean hasPrimaryFront = false;
+ for (int i = 0; i < mCameraIdsUnderTest.length; i++) {
+ String cameraId = mCameraIdsUnderTest[i];
+ boolean isPrimaryRear = CameraTestUtils.isPrimaryRearFacingCamera(
+ mCameraManager, cameraId);
+ boolean isPrimaryFront = CameraTestUtils.isPrimaryFrontFacingCamera(
+ mCameraManager, cameraId);
+ if (!isPrimaryRear && !isPrimaryFront) {
+ continue;
+ }
+
+ CameraCharacteristics c = mCharacteristics.get(i);
+ StaticMetadata staticInfo = mAllStaticInfo.get(cameraId);
+
+ // H-1-1, H-1-2
+ Size pixelArraySize = CameraTestUtils.getValueNotNull(
+ c, CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE);
+ long sensorResolution = pixelArraySize.getHeight() * pixelArraySize.getWidth();
+ StreamConfigurationMap config = staticInfo.getValueFromKeyNonNull(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ assertNotNull("No stream configuration map found for ID " + cameraId, config);
+ List<Size> videoSizes = CameraTestUtils.getSupportedVideoSizes(cameraId,
+ mCameraManager, null /*bound*/);
+
+ if (isPrimaryRear) {
+ hasPrimaryRear = true;
+ mCollector.expectTrue("Primary rear camera resolution should be at least " +
+ MIN_BACK_SENSOR_PERFORMANCE_CLASS_RESOLUTION + " pixels, is "+
+ sensorResolution,
+ sensorResolution >= MIN_BACK_SENSOR_PERFORMANCE_CLASS_RESOLUTION);
+
+ // 720P @ 240fps
+ boolean supportHighSpeed = staticInfo.isCapabilitySupported(CONSTRAINED_HIGH_SPEED);
+ mCollector.expectTrue("Primary rear camera should support high speed recording",
+ supportHighSpeed);
+ if (supportHighSpeed) {
+ boolean supportHD240 = false;
+ Size[] availableHighSpeedSizes = config.getHighSpeedVideoSizes();
+ for (Size size : availableHighSpeedSizes) {
+ if (!size.equals(HD)) {
+ continue;
+ }
+ Range<Integer>[] availableFpsRanges =
+ config.getHighSpeedVideoFpsRangesFor(size);
+ for (Range<Integer> fpsRange : availableFpsRanges) {
+ if (fpsRange.getUpper() == 240) {
+ supportHD240 = true;
+ break;
+ }
+ }
+ if (supportHD240) {
+ break;
+ }
+ }
+ mCollector.expectTrue("Primary rear camera should support HD @ 240fps",
+ supportHD240);
+ }
+
+ // 4K @ 30fps
+ boolean supportUHD = videoSizes.contains(UHD);
+ boolean supportDC4K = videoSizes.contains(DC4K);
+ mCollector.expectTrue("Primary rear camera should support 4k video recording",
+ supportUHD || supportDC4K);
+ if (supportUHD || supportDC4K) {
+ long minFrameDuration = config.getOutputMinFrameDuration(
+ android.media.MediaRecorder.class, supportDC4K ? DC4K : UHD);
+ mCollector.expectTrue("Primary rear camera should support 4k video @ 30fps",
+ minFrameDuration < (1e9 / 29.9));
+ }
+ } else {
+ hasPrimaryFront = true;
+ mCollector.expectTrue("Primary front camera resolution should be at least " +
+ MIN_FRONT_SENSOR_PERFORMANCE_CLASS_RESOLUTION + " pixels, is "+
+ sensorResolution,
+ sensorResolution >= MIN_FRONT_SENSOR_PERFORMANCE_CLASS_RESOLUTION);
+ // 1080P @ 30fps
+ boolean supportFULLHD = videoSizes.contains(FULLHD);
+ mCollector.expectTrue("Primary front camera should support 1080P video recording",
+ supportFULLHD);
+ if (supportFULLHD) {
+ long minFrameDuration = config.getOutputMinFrameDuration(
+ android.media.MediaRecorder.class, FULLHD);
+ mCollector.expectTrue("Primary front camera should support 1080P video @ 30fps",
+ minFrameDuration < (1e9 / 29.9));
+ }
+ }
+
+ // H-1-3
+ mCollector.expectTrue("Primary rear/front camera should be at least FULL, but is " +
+ staticInfo.getHardwareLevelChecked(), staticInfo.isHardwareLevelAtLeastFull());
+
+ // H-1-4
+ if (isPrimaryRear) {
+ mCollector.expectTrue("Primary rear camera should support RAW capability",
+ staticInfo.isCapabilitySupported(RAW));
+ }
+
+ // H-1-5
+ Integer timestampSource = c.get(CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE);
+ mCollector.expectTrue(
+ "Primary rear/front camera should support real-time timestamp source",
+ timestampSource != null &&
+ timestampSource.equals(CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME));
+
+ // H-1-8
+ Size[] jpegSizes = staticInfo.getJpegOutputSizesChecked();
+ assertTrue("Primary rear/front cameras must support JPEG formats",
+ jpegSizes != null && jpegSizes.length > 0);
+ for (Size jpegSize : jpegSizes) {
+ mCollector.expectTrue(
+ "Primary rear/front camera's JPEG size must be at least 1080p, but is " +
+ jpegSize,
+ jpegSize.getWidth() >= FULLHD.getWidth() &&
+ jpegSize.getHeight() >= FULLHD.getHeight());
+ }
+ }
+ mCollector.expectTrue("There must be a primary rear camera for S performance class.",
+ hasPrimaryRear);
+ mCollector.expectTrue("There must be a primary front camera for S performance class.",
+ hasPrimaryFront);
+ }
+
+ /**
* Get lens distortion coefficients, as a list of 6 floats; returns null if no valid
* distortion field is available
*/
diff --git a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
index b7b5061..10632ff 100644
--- a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
@@ -321,6 +321,7 @@
private void testSingleCaptureForFormat(int[] formats, String formatDescription,
boolean addPreviewDelay) throws Exception {
double[] avgResultTimes = new double[mTestRule.getCameraIdsUnderTest().length];
+ double[] avgCaptureTimes = new double[mTestRule.getCameraIdsUnderTest().length];
int counter = 0;
for (String id : mTestRule.getCameraIdsUnderTest()) {
@@ -376,11 +377,12 @@
SimpleImageListener[] imageListeners = new SimpleImageListener[formats.length];
Size[] imageSizes = new Size[formats.length];
for (int j = 0; j < formats.length; j++) {
+ Size sizeBound = mTestRule.isPerfClassTest() ? new Size(1920, 1080) : null;
imageSizes[j] = CameraTestUtils.getSortedSizesForFormat(
id,
mTestRule.getCameraManager(),
formats[j],
- /*bound*/null).get(0);
+ sizeBound).get(0);
imageListeners[j] = new SimpleImageListener();
}
@@ -454,6 +456,7 @@
ResultUnit.MS);
avgResultTimes[counter] = Stat.getAverage(getResultTimes);
+ avgCaptureTimes[counter] = Stat.getAverage(captureTimes);
}
finally {
CameraTestUtils.closeImageReaders(readers);
@@ -470,10 +473,19 @@
String streamName = appendFormatDescription("test_single_capture_average",
formatDescription);
mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName);
- String message = appendFormatDescription(
- "camera_capture_result_average_latency_for_all_cameras", formatDescription);
- mReportLog.setSummary(message, Stat.getAverage(avgResultTimes),
- ResultType.LOWER_BETTER, ResultUnit.MS);
+ // In performance measurement mode, capture the buffer latency rather than result
+ // latency.
+ if (mTestRule.isPerfMeasure()) {
+ String message = appendFormatDescription(
+ "camera_capture_average_latency_for_all_cameras", formatDescription);
+ mReportLog.setSummary(message, Stat.getAverage(avgCaptureTimes),
+ ResultType.LOWER_BETTER, ResultUnit.MS);
+ } else {
+ String message = appendFormatDescription(
+ "camera_capture_result_average_latency_for_all_cameras", formatDescription);
+ mReportLog.setSummary(message, Stat.getAverage(avgResultTimes),
+ ResultType.LOWER_BETTER, ResultUnit.MS);
+ }
mReportLog.submit(mInstrumentation);
}
}
diff --git a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestRule.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestRule.java
index 394f346..6f9eff1 100644
--- a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestRule.java
+++ b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestRule.java
@@ -92,9 +92,11 @@
private static final String CAMERA_ID_INSTR_ARG_KEY = "camera-id";
private static final String CAMERA_PERF_MEASURE = "perf-measure";
+ private static final String CAMERA_PERF_CLASS_TEST = "perf-class-test";
private static final Bundle mBundle = InstrumentationRegistry.getArguments();
private static final String mOverrideCameraId = mBundle.getString(CAMERA_ID_INSTR_ARG_KEY);
private static final String mPerfMeasure = mBundle.getString(CAMERA_PERF_MEASURE);
+ private static final String mPerfClassTest = mBundle.getString(CAMERA_PERF_CLASS_TEST);
public Camera2AndroidTestRule(Context context) {
mContext = context;
@@ -188,6 +190,10 @@
return mPerfMeasure != null && mPerfMeasure.equals("on");
}
+ public boolean isPerfClassTest() {
+ return mPerfClassTest != null && mPerfClassTest.equals("on");
+ }
+
private String[] deriveCameraIdsUnderTest() throws Exception {
String[] idsUnderTest = mCameraManager.getCameraIdList();
assertNotNull("Camera ids shouldn't be null", idsUnderTest);
diff --git a/tests/camera/src/android/hardware/cts/CameraTest.java b/tests/camera/src/android/hardware/cts/CameraTest.java
index cedf82c..a34465f 100644
--- a/tests/camera/src/android/hardware/cts/CameraTest.java
+++ b/tests/camera/src/android/hardware/cts/CameraTest.java
@@ -67,7 +67,7 @@
import java.util.List;
import java.util.TimeZone;
-import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.WindowUtil;
/**
* This test case must run with hardware. It can't be tested in emulator
@@ -139,7 +139,7 @@
// Some of the tests run on the UI thread. In case some of the operations take a long time to complete,
// wait for window to receive focus. This ensure that the focus event from input flinger has been handled,
// and avoids getting ANR.
- PollingCheck.waitFor(mActivityRule.getActivity()::hasWindowFocus);
+ WindowUtil.waitForFocus(mActivityRule.getActivity());
mCameraIds = CameraUtils.deriveCameraIdsUnderTest();
}
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
index 6737b54..7147442 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -52,6 +52,7 @@
import android.media.Image.Plane;
import android.os.Build;
import android.os.Handler;
+import android.os.SystemProperties;
import android.util.Log;
import android.util.Pair;
import android.util.Size;
@@ -3205,4 +3206,52 @@
}
return targetRange;
}
+
+ private static final int perfClass = SystemProperties.getInt(
+ "ro.odm.build.media_performance_class", 0);
+
+ private static final int PERFORMANCE_CLASS_S = Build.VERSION_CODES.R + 1;
+
+ /**
+ * Check whether this mobile device is S performance class as defined in CDD
+ */
+ public static boolean isSPerfClass() {
+ return perfClass == PERFORMANCE_CLASS_S;
+ }
+
+ /**
+ * Check whether a camera Id is a primary rear facing camera
+ */
+ public static boolean isPrimaryRearFacingCamera(CameraManager manager, String cameraId)
+ throws Exception {
+ return isPrimaryCamera(manager, cameraId, CameraCharacteristics.LENS_FACING_BACK);
+ }
+
+ /**
+ * Check whether a camera Id is a primary front facing camera
+ */
+ public static boolean isPrimaryFrontFacingCamera(CameraManager manager, String cameraId)
+ throws Exception {
+ return isPrimaryCamera(manager, cameraId, CameraCharacteristics.LENS_FACING_FRONT);
+ }
+
+ private static boolean isPrimaryCamera(CameraManager manager, String cameraId,
+ Integer lensFacing) throws Exception {
+ CameraCharacteristics characteristics;
+ Integer facing;
+
+ String [] ids = manager.getCameraIdList();
+ for (String id : ids) {
+ characteristics = manager.getCameraCharacteristics(id);
+ facing = characteristics.get(CameraCharacteristics.LENS_FACING);
+ if (lensFacing.equals(facing)) {
+ if (cameraId.equals(id)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+ return false;
+ }
}
diff --git a/tests/camera/utils/src/android/hardware/cts/helpers/CameraUtils.java b/tests/camera/utils/src/android/hardware/cts/helpers/CameraUtils.java
index 72a8318..05d43b7 100644
--- a/tests/camera/utils/src/android/hardware/cts/helpers/CameraUtils.java
+++ b/tests/camera/utils/src/android/hardware/cts/helpers/CameraUtils.java
@@ -81,6 +81,11 @@
Integer facing = ch.get(CameraCharacteristics.LENS_FACING);
switch (facing.intValue()) {
case CameraMetadata.LENS_FACING_EXTERNAL:
+ if (info.facing != Camera.CameraInfo.CAMERA_FACING_FRONT &&
+ info.facing != Camera.CameraInfo.CAMERA_FACING_BACK) {
+ return false;
+ }
+ break;
case CameraMetadata.LENS_FACING_FRONT:
if (info.facing != Camera.CameraInfo.CAMERA_FACING_FRONT) {
return false;
diff --git a/tests/framework/base/windowmanager/Android.mk b/tests/framework/base/windowmanager/Android.mk
index 8a7f090..c4fb78e 100644
--- a/tests/framework/base/windowmanager/Android.mk
+++ b/tests/framework/base/windowmanager/Android.mk
@@ -30,6 +30,8 @@
LOCAL_ASSET_DIR := $(LOCAL_PATH)/intent_tests
LOCAL_PACKAGE_NAME := CtsWindowManagerDeviceTestCases
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index ca0ea74..c66a71a 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -139,6 +139,9 @@
<activity android:name="android.server.wm.lifecycle.ActivityLifecycleClientTestBase$ResultActivity"/>
+ <activity android:name="android.server.wm.lifecycle.ActivityLifecycleClientTestBase$TranslucentResultActivity"
+ android:theme="@android:style/Theme.Dialog"/>
+
<activity android:name="android.server.wm.lifecycle.ActivityLifecycleClientTestBase$SingleTopActivity"
android:launchMode="singleTop" />
diff --git a/tests/framework/base/windowmanager/OWNERS b/tests/framework/base/windowmanager/OWNERS
index 2efb8fc..aa788b8 100644
--- a/tests/framework/base/windowmanager/OWNERS
+++ b/tests/framework/base/windowmanager/OWNERS
@@ -1,4 +1,31 @@
-# Bug component: 316125
-include ../OWNERS
-louischang@google.com
-riddlehsu@google.com
+# animation & tranistion
+# Bug template url: https://b.corp.google.com/issues/new?component=316275&template=1018192 = per-file *Transition*, SplashscreenTests.java
+# foldables
+# Bug template url: https://b.corp.google.com/issues/new?component=943781&template=1502790 = per-file *WindowContext*, *WindowMetrics*
+# insets & cutout
+# Bug template url: https://b.corp.google.com/issues/new?component=339570&template=1037597 = per-file *Inset*, *Cutout*, *RoundedCorner*, ForceRelayoutTest.java
+# shell
+# Bug template url: https://b.corp.google.com/issues/new?component=928594&template=1490782 = per-file DragDropTest.java
+# surface
+# Bug template url: https://b.corp.google.com/issues/new?component=316245&template=1018194 = per-file DisplayHashManagerTest.java, *Surface*
+# activity
+# Bug template url: https://b.corp.google.com/issues/new?component=316020&template=1018174 = per-file *Config*, Activity*, AmStartOptionsTests.java, AspectRatioTests.java, AssistantStackTests.java, CloseOnOutsideTests.java
+# multi-display
+# Bug template url: https://b.corp.google.com/issues/new?component=316280&template=1018196 = per-file MultiDisplay*, *DisplayTest*, PresentationTest.java
+# pip
+# Bug template url: https://b.corp.google.com/issues/new?component=316251&template=1018197 = per-file PinnedStackTests.java
+# bubbles
+# Bug template url: https://b.corp.google.com/issues/new?component=555586&template=1210986 = per-file ActivityViewTest.java
+# split-screen
+# Bug template url: https://b.corp.google.com/issues/new?component=928697&template=1490890 = per-file MultiWindowTests.java, ReplaceWindowTests.java
+# app-compat
+# Bug template url: https://b.corp.google.com/issues/new?component=970984&template=1516678 = per-file *Compat*, DeprecatedTargetSdkTest.java, DisplaySizeTest.java, PrereleaseSdkTest.java
+# freeform
+# Bug template url: https://b.corp.google.com/issues/new?component=929241&template=1490914 = per-file *Freeform*
+# input
+# Bug template url: https://b.corp.google.com/issues/new?component=136048&template=115201 = per-file *Input*, *Touch*
+# Ime
+# Bug template url: https://b.corp.google.com/issues/new?component=34867&template=195938 = per-file *Ime*
+# others
+# Bug template url: https://b.corp.google.com/issues/new?component=316125&template=1018199
+include platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS
diff --git a/tests/framework/base/windowmanager/app/AndroidManifest.xml b/tests/framework/base/windowmanager/app/AndroidManifest.xml
index c6ab9f2..2a800eb 100755
--- a/tests/framework/base/windowmanager/app/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/app/AndroidManifest.xml
@@ -434,7 +434,7 @@
<activity android:name=".ShowWhenLockedAttrRotationActivity"
android:showWhenLocked="true"
- android:configChanges="orientation|screenSize"
+ android:configChanges="orientation|screenSize|screenLayout"
android:exported="true" />
<activity android:name=".ToastActivity"
diff --git a/tests/framework/base/windowmanager/jetpack/OWNERS b/tests/framework/base/windowmanager/jetpack/OWNERS
new file mode 100644
index 0000000..72fa917
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/OWNERS
@@ -0,0 +1,2 @@
+# Bug template url: https://b.corp.google.com/issues/new?component=812646&template=1393556
+akulian@google.com
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AssistantStackTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AssistantStackTests.java
index d777db2..7259720 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AssistantStackTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AssistantStackTests.java
@@ -68,6 +68,7 @@
public class AssistantStackTests extends ActivityManagerTestBase {
private int mAssistantDisplayId = DEFAULT_DISPLAY;
+ private int mDefaultWindowingMode;
public void setUp() throws Exception {
super.setUp();
@@ -78,6 +79,7 @@
WindowManagerState.ActivityTask assistantStack =
mWmState.getStackByActivityType(ACTIVITY_TYPE_ASSISTANT);
mAssistantDisplayId = assistantStack.mDisplayId;
+ mDefaultWindowingMode = getDefaultDisplayWindowingMode();
}
}
@@ -92,6 +94,8 @@
// Ensure that the activity launched in the fullscreen assistant stack
assertAssistantStackExists();
+ // In a multi-window environment the assistant might not be fullscreen
+ assumeTrue(mDefaultWindowingMode == WINDOWING_MODE_FULLSCREEN);
assertTrue("Expected assistant stack to be fullscreen",
mWmState.getStackByActivityType(
ACTIVITY_TYPE_ASSISTANT).isFullscreen());
@@ -137,7 +141,7 @@
@Test
public void testAssistantStackLaunchNewTask() throws Exception {
- assertAssistantStackCanLaunchAndReturnFromNewTask(WINDOWING_MODE_FULLSCREEN);
+ assertAssistantStackCanLaunchAndReturnFromNewTask(mDefaultWindowingMode);
}
@Test
@@ -183,9 +187,9 @@
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT);
} else {
mWmState.assertFocusedActivity("TestActivity should be resumed", TEST_ACTIVITY);
- mWmState.assertFrontStack("Fullscreen stack should be on top.",
+ mWmState.assertFrontStack("TestActivity stack should be on top.",
expectedWindowingMode, ACTIVITY_TYPE_STANDARD);
- mWmState.assertFocusedStack("Fullscreen stack should be focused.",
+ mWmState.assertFocusedStack("TestActivity stack should be focused.",
expectedWindowingMode, ACTIVITY_TYPE_STANDARD);
}
@@ -219,14 +223,14 @@
getActivityName(ASSISTANT_ACTIVITY) + " finished");
}
waitForValidStateWithActivityTypeAndWindowingMode(
- TEST_ACTIVITY, ACTIVITY_TYPE_STANDARD, WINDOWING_MODE_FULLSCREEN);
+ TEST_ACTIVITY, ACTIVITY_TYPE_STANDARD, mDefaultWindowingMode);
waitAndAssertTopResumedActivity(TEST_ACTIVITY, mAssistantDisplayId,
"TestActivity should be resumed");
mWmState.assertFocusedActivity("TestActivity should be focused", TEST_ACTIVITY);
mWmState.assertFrontStack("Fullscreen stack should be on top.",
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ mDefaultWindowingMode, ACTIVITY_TYPE_STANDARD);
mWmState.assertFocusedStack("Fullscreen stack should be focused.",
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ mDefaultWindowingMode, ACTIVITY_TYPE_STANDARD);
}
@Test
@@ -282,9 +286,12 @@
EXTRA_ASSISTANT_IS_TRANSLUCENT, "true",
EXTRA_ASSISTANT_LAUNCH_NEW_TASK, getActivityName(TEST_ACTIVITY));
waitForValidStateWithActivityTypeAndWindowingMode(
- TEST_ACTIVITY, ACTIVITY_TYPE_STANDARD, WINDOWING_MODE_FULLSCREEN);
+ TEST_ACTIVITY, ACTIVITY_TYPE_STANDARD, mDefaultWindowingMode);
final ComponentName homeActivity = mWmState.getHomeActivityName();
+ int windowingMode = mWmState.getFocusedStackWindowingMode();
+ // In a multi-window environment the home activity might not be fully covered
+ assumeTrue(windowingMode == WINDOWING_MODE_FULLSCREEN);
mWmState.waitAndAssertVisibilityGone(homeActivity);
mBroadcastActionTrigger.doAction(TEST_ACTIVITY_ACTION_FINISH_SELF);
mWmState.waitForFocusedStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT);
@@ -410,6 +417,14 @@
return mAssistantDisplayId == DEFAULT_DISPLAY;
}
+ /**
+ * @return Windowing Mode from the default display
+ */
+ private int getDefaultDisplayWindowingMode() {
+ mWmState.computeState();
+ return mWmState.getDisplay(DEFAULT_DISPLAY).getWindowingMode();
+ }
+
/** Helper class to save, set, and restore
* {@link Settings.Secure#VOICE_INTERACTION_SERVICE} system preference.
*/
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DreamManagerServiceTests.java b/tests/framework/base/windowmanager/src/android/server/wm/DreamManagerServiceTests.java
index ddc8163..4edd318 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DreamManagerServiceTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DreamManagerServiceTests.java
@@ -33,6 +33,7 @@
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
import android.view.Surface;
+import android.content.res.Resources;
import androidx.test.filters.FlakyTest;
@@ -62,7 +63,9 @@
}
@Before
- public void setDreamEnabled() {
+ public void setup() {
+ assumeTrue("Skipping test: no dream support", supportsDream());
+
mDefaultDreamServiceEnabled =
Settings.Secure.getInt(mContext.getContentResolver(),
"screensaver_enabled", 1) != 0;
@@ -74,7 +77,7 @@
}
@After
- public void resetDreamEnabled() {
+ public void reset() {
if (!mDefaultDreamServiceEnabled) {
SystemUtil.runWithShellPermissionIdentity(() -> {
Settings.Secure.putInt(mContext.getContentResolver(), "screensaver_enabled", 0);
@@ -111,6 +114,11 @@
});
}
+ private boolean supportsDream() {
+ return mContext.getResources().getBoolean(
+ Resources.getSystem().getIdentifier("config_dreamsSupported", "bool", "android"));
+ }
+
private void assertDreamActivityGone() {
mWmState.computeState();
assertTrue(!mWmState.containsWindow(getWindowName(mDreamActivityName))
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardLockedTests.java b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardLockedTests.java
index 115310f..1654839 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardLockedTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardLockedTests.java
@@ -390,7 +390,7 @@
lockScreenSession.setLockCredential().gotoKeyguard();
assertTrue("Keyguard is showing", mWmState.getKeyguardControllerState().keyguardShowing);
- lockScreenSession.enterAndConfirmLockCredential();
+ lockScreenSession.unlockDevice().enterAndConfirmLockCredential();
mWmState.waitAndAssertKeyguardGone();
final ImeEventStream stream = mockImeSession.openEventStream();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
index 44bd353..86de555 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
@@ -196,6 +196,11 @@
*/
@Test
public void testLaunchExternalDisplayActivityWhilePrimaryOff() {
+ if (isOperatorTierDevice()) {
+ // This test is not applicable for the device who uses launch_after_boot configuration
+ return;
+ }
+
// Launch something on the primary display so we know there is a resumed activity there
launchActivity(RESIZEABLE_ACTIVITY);
waitAndAssertTopResumedActivity(RESIZEABLE_ACTIVITY, DEFAULT_DISPLAY,
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
index 0dd955e..2e1b5c9 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
@@ -543,9 +543,9 @@
// Expect onStartInput / showSoftInput would be executed when user tapping on the
// non-system created display intentionally.
- final Rect drawRect = new Rect();
- imeTestActivitySession.getActivity().mEditText.getDrawingRect(drawRect);
- tapOnDisplaySync(drawRect.left, drawRect.top, newDisplay.mId);
+ final int[] location = new int[2];
+ imeTestActivitySession.getActivity().mEditText.getLocationOnScreen(location);
+ tapOnDisplaySync(location[0], location[1], newDisplay.mId);
// Verify the activity to show soft input on the default display.
final ImeEventStream stream = mockImeSession.openEventStream();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
index 35b06ba..46b706a 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
@@ -16,6 +16,7 @@
package android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.server.wm.WindowInsetsAnimationControllerTests.ControlListener.Event.CANCELLED;
import static android.server.wm.WindowInsetsAnimationControllerTests.ControlListener.Event.FINISHED;
import static android.server.wm.WindowInsetsAnimationControllerTests.ControlListener.Event.READY;
@@ -152,7 +153,7 @@
mockImeEventStream = null;
}
- mActivity = startActivity(TestActivity.class);
+ mActivity = startActivityInWindowingMode(TestActivity.class, WINDOWING_MODE_FULLSCREEN);
mRootView = mActivity.getWindow().getDecorView();
mListener = new ControlListener(mErrorCollector);
assumeTestCompatibility();
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 b384588..60afe29 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
@@ -408,7 +408,8 @@
// Swiping from top of display can show bars.
dragFromTopToCenter(rootView);
- PollingCheck.waitFor(TIMEOUT, () -> rootView.getRootWindowInsets().isVisible(types));
+ PollingCheck.waitFor(TIMEOUT, () -> rootView.getRootWindowInsets().isVisible(types)
+ && rootView.getSystemUiVisibility() != targetFlags);
// Use flags to hide status bar again.
ANIMATION_CALLBACK.reset();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsLayoutTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsLayoutTests.java
index e622ad3..4838c01 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsLayoutTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsLayoutTests.java
@@ -27,15 +27,15 @@
import static org.junit.Assert.assertEquals;
import android.graphics.Insets;
-import android.graphics.Point;
+import android.graphics.Rect;
import android.os.Bundle;
import android.platform.test.annotations.Presubmit;
-import android.view.Display;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Type;
import android.view.WindowManager;
+import android.view.WindowMetrics;
import androidx.annotation.Nullable;
import androidx.test.filters.FlakyTest;
@@ -68,7 +68,7 @@
PollingCheck.waitFor(TIMEOUT, () -> mainWindowRoot.getWidth() > 0);
getInstrumentation().runOnMainSync(() -> {
- activity.assertMatchDisplay();
+ activity.assertMatchesWindowBounds();
});
testSetFitInsetsTypesInner(Type.statusBars(), activity, mainWindowRoot);
@@ -112,7 +112,7 @@
PollingCheck.waitFor(TIMEOUT, () -> mainWindowRoot.getWidth() > 0);
getInstrumentation().runOnMainSync(() -> {
- activity.assertMatchDisplay();
+ activity.assertMatchesWindowBounds();
});
testSetFitInsetsSidesInner(Side.LEFT, activity, mainWindowRoot);
@@ -163,7 +163,7 @@
final int[] locationAndSize2 = new int[4];
getInstrumentation().runOnMainSync(() -> {
- activity.assertMatchDisplay();
+ activity.assertMatchesWindowBounds();
activity.addChildWindow(types, sides, false);
});
@@ -232,17 +232,16 @@
return mChildWindowRoot;
}
- void assertMatchDisplay() {
+ void assertMatchesWindowBounds() {
final View rootView = getWindow().getDecorView();
- final Display display = rootView.getDisplay();
- final Point size = new Point();
- display.getRealSize(size);
- assertEquals(size.x, rootView.getWidth());
- assertEquals(size.y, rootView.getHeight());
+ final Rect windowMetricsBounds =
+ getWindowManager().getCurrentWindowMetrics().getBounds();
+ assertEquals(windowMetricsBounds.width(), rootView.getWidth());
+ assertEquals(windowMetricsBounds.height(), rootView.getHeight());
final int[] locationOnScreen = new int[2];
rootView.getLocationOnScreen(locationOnScreen);
- assertEquals(0 /* expected x */, locationOnScreen[0]);
- assertEquals(0 /* expected y */, locationOnScreen[1]);
+ assertEquals(locationOnScreen[0] /* expected x */, windowMetricsBounds.left);
+ assertEquals(locationOnScreen[1] /* expected y */, windowMetricsBounds.top);
}
}
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/intent/OWNERS b/tests/framework/base/windowmanager/src/android/server/wm/intent/OWNERS
new file mode 100644
index 0000000..b923e94
--- /dev/null
+++ b/tests/framework/base/windowmanager/src/android/server/wm/intent/OWNERS
@@ -0,0 +1,2 @@
+# Bug template url: https://b.corp.google.com/issues/new?component=316020&template=1018174
+louischang@google.com
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 58b6325..0308a38 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
@@ -496,6 +496,8 @@
public static final String EXTRA_LAUNCH_ON_RESULT = "LAUNCH_ON_RESULT";
public static final String EXTRA_LAUNCH_ON_RESUME_AFTER_RESULT =
"LAUNCH_ON_RESUME_AFTER_RESULT";
+ public static final String EXTRA_USE_TRANSLUCENT_RESULT =
+ "USE_TRANSLUCENT_RESULT";
boolean mReceivedResultOk;
@@ -511,7 +513,14 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- final Intent intent = new Intent(this, ResultActivity.class);
+
+ final Intent intent;
+ if (getIntent().hasExtra(EXTRA_USE_TRANSLUCENT_RESULT)) {
+ intent = new Intent(this, TranslucentResultActivity.class);
+ } else {
+ intent = new Intent(this, ResultActivity.class);
+ }
+
final Bundle forwardExtras = getIntent().getBundleExtra(EXTRA_FORWARD_EXTRAS);
if (forwardExtras != null) {
intent.putExtras(forwardExtras);
@@ -539,6 +548,15 @@
}
/** Test activity that is started for result. */
+ public static class TranslucentResultActivity extends CallbackTrackingActivity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ setResult(RESULT_OK);
+ super.onCreate(savedInstanceState);
+ }
+ }
+
+ /** Test activity that is started for result. */
public static class ResultActivity extends CallbackTrackingActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
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 3c8132c..22001a5 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
@@ -135,7 +135,7 @@
.setOptions(launchOptions)
.launch();
- final Activity secondActivity = launchActivityInFullscreenAndWait(SecondActivity.class);
+ final Activity secondActivity = launchActivityAndWait(SecondActivity.class);
new Launcher(ThirdActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
@@ -193,8 +193,7 @@
.setOptions(launchOptions)
.launch();
- final Activity transparentActivity =
- launchActivityInFullscreenAndWait(TranslucentActivity.class);
+ final Activity transparentActivity = launchActivityAndWait(TranslucentActivity.class);
new Launcher(ThirdActivity.class)
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
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 7bbf9c1..68ebae9 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
@@ -238,6 +238,7 @@
getLifecycleLog().clear();
final Activity launchForResultActivity = new Launcher(LaunchForResultActivity.class)
.customizeIntent(LaunchForResultActivity.forwardFlag(EXTRA_FINISH_IN_ON_RESUME))
+ .setExtraFlags(LaunchForResultActivity.EXTRA_USE_TRANSLUCENT_RESULT)
.launch();
waitAndAssertActivityStates(state(baseActivity, ON_STOP));
@@ -252,7 +253,7 @@
Arrays.asList(
PRE_ON_CREATE, ON_CREATE, ON_START, ON_POST_CREATE, ON_RESUME,
ON_TOP_POSITION_GAINED);
- waitForActivityTransitions(ResultActivity.class, expectedTopActivitySequence);
+ waitForActivityTransitions(TranslucentResultActivity.class, expectedTopActivitySequence);
LifecycleVerifier.assertEntireSequence(Arrays.asList(
transition(CallbackTrackingActivity.class, ON_TOP_POSITION_LOST),
@@ -265,19 +266,19 @@
transition(LaunchForResultActivity.class, ON_TOP_POSITION_GAINED),
transition(LaunchForResultActivity.class, ON_TOP_POSITION_LOST),
transition(LaunchForResultActivity.class, ON_PAUSE),
- transition(ResultActivity.class, PRE_ON_CREATE),
- transition(ResultActivity.class, ON_CREATE),
- transition(ResultActivity.class, ON_START),
- transition(ResultActivity.class, ON_POST_CREATE),
- transition(ResultActivity.class, ON_RESUME),
- transition(ResultActivity.class, ON_TOP_POSITION_GAINED),
- transition(ResultActivity.class, ON_TOP_POSITION_LOST),
- transition(ResultActivity.class, ON_PAUSE),
+ transition(TranslucentResultActivity.class, PRE_ON_CREATE),
+ transition(TranslucentResultActivity.class, ON_CREATE),
+ transition(TranslucentResultActivity.class, ON_START),
+ transition(TranslucentResultActivity.class, ON_POST_CREATE),
+ transition(TranslucentResultActivity.class, ON_RESUME),
+ transition(TranslucentResultActivity.class, ON_TOP_POSITION_GAINED),
+ transition(TranslucentResultActivity.class, ON_TOP_POSITION_LOST),
+ transition(TranslucentResultActivity.class, ON_PAUSE),
transition(LaunchForResultActivity.class, ON_ACTIVITY_RESULT),
transition(LaunchForResultActivity.class, ON_RESUME),
transition(LaunchForResultActivity.class, ON_TOP_POSITION_GAINED),
- transition(ResultActivity.class, ON_STOP),
- transition(ResultActivity.class, ON_DESTROY),
+ transition(TranslucentResultActivity.class, ON_STOP),
+ transition(TranslucentResultActivity.class, ON_DESTROY),
transition(CallbackTrackingActivity.class, ON_STOP)),
getLifecycleLog(), "Double launch sequence must match");
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/OWNERS b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/OWNERS
new file mode 100644
index 0000000..1bcd73d
--- /dev/null
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/OWNERS
@@ -0,0 +1,2 @@
+# Bug template url: https://b.corp.google.com/issues/new?component=316020&template=1018174
+include /tests/framework/base/windowmanager/src/android/server/wm/intent/OWNERS
diff --git a/tests/framework/base/windowmanager/testsdk28/src/android/server/wm/AspectRatioSdk28Tests.java b/tests/framework/base/windowmanager/testsdk28/src/android/server/wm/AspectRatioSdk28Tests.java
index ea1a00a..30a94df 100644
--- a/tests/framework/base/windowmanager/testsdk28/src/android/server/wm/AspectRatioSdk28Tests.java
+++ b/tests/framework/base/windowmanager/testsdk28/src/android/server/wm/AspectRatioSdk28Tests.java
@@ -20,7 +20,8 @@
import static androidx.test.InstrumentationRegistry.getInstrumentation;
-import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
import android.app.Activity;
import android.platform.test.annotations.Presubmit;
@@ -37,9 +38,6 @@
@Presubmit
public class AspectRatioSdk28Tests extends AspectRatioTestsBase {
- // The minimum supported device aspect ratio for pre-Q devices.
- private static final float MIN_DEVICE_ASPECT_RATIO = 1.333f;
-
// The minimum supported device aspect ratio for watches.
private static final float MIN_WATCH_DEVICE_ASPECT_RATIO = 1.0f;
@@ -53,14 +51,17 @@
Sdk28MinAspectRatioActivity.class, false /* initialTouchMode */,
false /* launchActivity */);
+ /**
+ * Device implementations with the Configuration.uiMode set as UI_MODE_TYPE_WATCH MUST have an
+ * aspect ratio value set as 1.0
+ */
@Test
- public void testMaxAspectRatioPreQActivity() {
- boolean isWatch = getInstrumentation().getContext().getPackageManager()
- .hasSystemFeature(FEATURE_WATCH);
- float minAspectRatio = isWatch ? MIN_WATCH_DEVICE_ASPECT_RATIO : MIN_DEVICE_ASPECT_RATIO;
+ public void testMinAspectRatioPreQActivityOnWatch() {
+ // Only test for watch.
+ assumeTrue(getInstrumentation().getContext().getPackageManager()
+ .hasSystemFeature(FEATURE_WATCH));
- runAspectRatioTest(mSdk28MinAspectRatioActivity, (actual, displayId, size) -> {
- assertThat(actual, greaterThanOrEqualToInexact(minAspectRatio));
- });
+ runAspectRatioTest(mSdk28MinAspectRatioActivity, (actual, displayId, size) ->
+ assertEquals(actual, MIN_WATCH_DEVICE_ASPECT_RATIO, 0.0f));
}
}
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 03fe4a5..9e11ebb 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
@@ -1083,6 +1083,10 @@
return mContext.getResources().getConfiguration().smallestScreenWidthDp >= 600;
}
+ protected boolean isOperatorTierDevice() {
+ return hasDeviceFeature("com.google.android.tv.operator_tier");
+ }
+
protected void waitAndAssertActivityState(ComponentName activityName,
String state, String message) {
mWmState.waitForActivityState(activityName, state);
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/WaitForValidActivityState.java b/tests/framework/base/windowmanager/util/src/android/server/wm/WaitForValidActivityState.java
index fd9127d..486e612 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/WaitForValidActivityState.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/WaitForValidActivityState.java
@@ -95,7 +95,7 @@
case WINDOWING_MODE_FREEFORM: return "FREEFORM";
case WINDOWING_MODE_MULTI_WINDOW: return "MULTI_WINDOW";
default:
- throw new IllegalArgumentException("Unknown WINDOWING_MODE_: " + windowingMode);
+ return "Unknown WINDOWING_MODE_: " + windowingMode;
}
}
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsControllerTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsControllerTest.java
index dd8d070..f2d1761 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsControllerTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsControllerTest.java
@@ -89,7 +89,7 @@
}
private static final int INITIAL_KEYBOARD_HEIGHT = 200;
- private static final int NEW_KEYBOARD_HEIGHT = 400;
+ private static final int NEW_KEYBOARD_HEIGHT = 300;
@Test
public void testChangeSizeWhileControlling() throws Exception {
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsVisibilityTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsVisibilityTest.java
index d104450..06fe578 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsVisibilityTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsVisibilityTest.java
@@ -34,6 +34,8 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.os.SystemClock;
@@ -77,7 +79,7 @@
@RunWith(AndroidJUnit4.class)
public class ImeInsetsVisibilityTest extends EndToEndImeTestBase {
private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5);
- private static final int NEW_KEYBOARD_HEIGHT = 400;
+ private static final int NEW_KEYBOARD_HEIGHT = 300;
private static final String TEST_MARKER_PREFIX =
"android.view.inputmethod.cts.ImeInsetsVisibilityTest";
@@ -177,9 +179,23 @@
Point lastEditTextPos = new Point(curEditPos);
curEditPos = getLocationOnScreenForView(editText);
- assertTrue("Insets should visible and EditText position should be adjusted",
- isInsetsVisible(insetsFromActivity[0], WindowInsets.Type.ime())
- && curEditPos.y < lastEditTextPos.y);
+ // Watch doesn't support navigation bar and has limited screen size, so no transition
+ // in editbox with respect to x and y coordinates
+ Configuration config = InstrumentationRegistry.getInstrumentation()
+ .getContext()
+ .getResources()
+ .getConfiguration();
+ boolean isSmallScreenLayout =
+ config.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_SMALL);
+
+ if (isSmallScreenLayout) {
+ assertTrue("Insets should visible",
+ isInsetsVisible(insetsFromActivity[0], WindowInsets.Type.ime()));
+ } else {
+ assertTrue("Insets should visible and EditText position should be adjusted",
+ isInsetsVisible(insetsFromActivity[0], WindowInsets.Type.ime())
+ && curEditPos.y < lastEditTextPos.y);
+ }
imm.showInputMethodPicker();
TestUtils.waitOnMainUntil(() -> imm.isInputMethodPickerShown() && editText.isLaidOut(),
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceStrictModeTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceStrictModeTest.java
new file mode 100644
index 0000000..2f3541c
--- /dev/null
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodServiceStrictModeTest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod.cts;
+
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE;
+
+import static com.android.cts.mockime.ImeEventStreamTestUtils.clearAllEvents;
+import static com.android.cts.mockime.ImeEventStreamTestUtils.expectCommand;
+import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEvent;
+import static com.android.cts.mockime.ImeEventStreamTestUtils.notExpectEvent;
+
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.inputmethodservice.InputMethodService;
+import android.os.StrictMode;
+import android.view.inputmethod.cts.util.EndToEndImeTestBase;
+import android.view.inputmethod.cts.util.TestActivity;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+
+import androidx.annotation.IntDef;
+import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.cts.mockime.ImeEvent;
+import com.android.cts.mockime.ImeEventStream;
+import com.android.cts.mockime.ImeSettings;
+import com.android.cts.mockime.MockImeSession;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.TimeUnit;
+
+/** Tests for verifying {@link StrictMode} violations on {@link InputMethodService} APIs. */
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class InputMethodServiceStrictModeTest extends EndToEndImeTestBase {
+ private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5);
+ private static final long EXPECTED_TIMEOUT = TimeUnit.SECONDS.toMillis(2);
+
+ /**
+ * Verifies if {@link Context#getDisplay} from {@link InputMethodService} and context created
+ * from {@link InputMethodService#createConfigurationContext(Configuration)} violates
+ * incorrect context violation.
+ */
+ private static final int VERIFY_MODE_GET_DISPLAY = 1;
+ /**
+ * Verifies if get {@link android.view.WindowManager} from {@link InputMethodService} and
+ * context created from {@link InputMethodService#createConfigurationContext(Configuration)}
+ * violates incorrect context violation.
+ *
+ * @see Context#getSystemService(String)
+ * @see Context#getSystemService(Class)
+ */
+ private static final int VERIFY_MODE_GET_WINDOW_MANAGER = 2;
+ /**
+ * Verifies if passing {@link InputMethodService} and context created
+ * from {@link InputMethodService#createConfigurationContext(Configuration)} to
+ * {@link android.view.ViewConfiguration#get(Context)} violates incorrect context violation.
+ */
+ private static final int VERIFY_MODE_GET_VIEW_CONFIGURATION = 3;
+
+ /**
+ * Verify mode to verifying if APIs violates incorrect context violation.
+ *
+ * @see #VERIFY_MODE_GET_DISPLAY
+ * @see #VERIFY_MODE_GET_WINDOW_MANAGER
+ * @see #VERIFY_MODE_GET_VIEW_CONFIGURATION
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {
+ VERIFY_MODE_GET_DISPLAY,
+ VERIFY_MODE_GET_WINDOW_MANAGER,
+ VERIFY_MODE_GET_VIEW_CONFIGURATION,
+ })
+ private @interface VerifyMode {}
+
+ @Test
+ public void testIncorrectContextUseOnGetSystemService() throws Exception {
+ verifyIms(VERIFY_MODE_GET_WINDOW_MANAGER);
+ }
+
+ @Test
+ public void testIncorrectContextUseOnGetDisplay() throws Exception {
+ verifyIms(VERIFY_MODE_GET_DISPLAY);
+ }
+
+ @Test
+ public void testIncorrectContextUse_GetViewConfiguration() throws Exception {
+ verifyIms(VERIFY_MODE_GET_VIEW_CONFIGURATION);
+ }
+
+ /**
+ * Verify if APIs violates incorrect context violations by {@code mode}.
+ *
+ * @see VerifyMode
+ */
+ private void verifyIms(@VerifyMode int mode) throws Exception {
+ try (MockImeSession imeSession = MockImeSession.create(
+ InstrumentationRegistry.getInstrumentation().getContext(),
+ InstrumentationRegistry.getInstrumentation().getUiAutomation(),
+ new ImeSettings.Builder().setStrictModeEnabled(true))) {
+ final ImeEventStream stream = imeSession.openEventStream();
+
+ createTestActivity(SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+ expectEvent(stream, event -> "onStartInput".equals(event.getEventName()), TIMEOUT);
+
+ final ImeEventStream forkedStream = clearAllEvents(stream, "onStrictModeViolated");
+ final ImeEvent imeEvent;
+ switch (mode) {
+ case VERIFY_MODE_GET_DISPLAY:
+ imeEvent = expectCommand(forkedStream, imeSession.callVerifyGetDisplay(),
+ TIMEOUT);
+ break;
+ case VERIFY_MODE_GET_WINDOW_MANAGER:
+ imeEvent = expectCommand(forkedStream, imeSession.callVerifyGetWindowManager(),
+ TIMEOUT);
+ break;
+ case VERIFY_MODE_GET_VIEW_CONFIGURATION:
+ imeEvent = expectCommand(forkedStream,
+ imeSession.callVerifyGetViewConfiguration(), TIMEOUT);
+ break;
+ default:
+ imeEvent = null;
+ }
+ assertTrue(imeEvent.getReturnBooleanValue());
+ notExpectEvent(stream, event -> "onStrictModeViolated".equals(event.getEventName()),
+ EXPECTED_TIMEOUT);
+ }
+ }
+
+ private TestActivity createTestActivity(final int windowFlags) {
+ return TestActivity.startSync(activity -> {
+ final LinearLayout layout = new LinearLayout(activity);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+ final EditText editText = new EditText(activity);
+ editText.setText("Editable");
+ layout.addView(editText);
+ editText.requestFocus();
+
+ activity.getWindow().setSoftInputMode(windowFlags);
+ return layout;
+ });
+ }
+}
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
index cad3309..7b4b0f6 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
@@ -36,9 +36,11 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
import android.app.AlertDialog;
import android.app.Instrumentation;
+import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.SystemClock;
import android.support.test.uiautomator.UiObject2;
@@ -270,6 +272,10 @@
@Test
public void testShowHideKeyboardOnWebView() throws Exception {
+ final PackageManager pm =
+ InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
+ assumeTrue(pm.hasSystemFeature("android.software.webview"));
+
try (MockImeSession imeSession = MockImeSession.create(
InstrumentationRegistry.getInstrumentation().getContext(),
InstrumentationRegistry.getInstrumentation().getUiAutomation(),
diff --git a/tests/libcore/jsr166/Android.bp b/tests/libcore/jsr166/Android.bp
index 67fb0b74..0ab6329 100644
--- a/tests/libcore/jsr166/Android.bp
+++ b/tests/libcore/jsr166/Android.bp
@@ -37,5 +37,6 @@
test_suites: [
"cts",
"general-tests",
+ "mts",
],
}
diff --git a/tests/libcore/jsr166/AndroidTest.xml b/tests/libcore/jsr166/AndroidTest.xml
index f2aaee5..93a2b76 100644
--- a/tests/libcore/jsr166/AndroidTest.xml
+++ b/tests/libcore/jsr166/AndroidTest.xml
@@ -45,4 +45,13 @@
<object type="module_controller" class="com.android.tradefed.testtype.suite.module.TestFailureModuleController">
<option name="screenshot-on-failure" value="false" />
</object>
+
+ <!-- When this test is run in a Mainline context (e.g. with `mts-tradefed`), only enable it if
+ one of the Mainline modules below is present on the device used for testing. -->
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <!-- ART Mainline Module (internal version). -->
+ <option name="mainline-module-package-name" value="com.google.android.art" />
+ <!-- ART Mainline Module (external (AOSP) version). -->
+ <option name="mainline-module-package-name" value="com.android.art" />
+ </object>
</configuration>
diff --git a/tests/libcore/luni/AndroidTest.xml b/tests/libcore/luni/AndroidTest.xml
index 59857db..2173c92 100644
--- a/tests/libcore/luni/AndroidTest.xml
+++ b/tests/libcore/luni/AndroidTest.xml
@@ -73,7 +73,7 @@
</object>
<!-- When this test is run in a Mainline context (e.g. with `mts-tradefed`), only enable it if
- one the Mainline modules below is present on the device used for testing. -->
+ one of the Mainline modules below is present on the device used for testing. -->
<object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
<!-- ART Mainline Module (internal version). -->
<option name="mainline-module-package-name" value="com.google.android.art" />
diff --git a/tests/libcore/ojluni/AndroidTest.xml b/tests/libcore/ojluni/AndroidTest.xml
index d69101e..86e04f6 100644
--- a/tests/libcore/ojluni/AndroidTest.xml
+++ b/tests/libcore/ojluni/AndroidTest.xml
@@ -49,4 +49,13 @@
<object type="module_controller" class="com.android.tradefed.testtype.suite.module.TestFailureModuleController">
<option name="screenshot-on-failure" value="false" />
</object>
+
+ <!-- When this test is run in a Mainline context (e.g. with `mts-tradefed`), only enable it if
+ one of the Mainline modules below is present on the device used for testing. -->
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <!-- ART Mainline Module (internal version). -->
+ <option name="mainline-module-package-name" value="com.google.android.art" />
+ <!-- ART Mainline Module (external (AOSP) version). -->
+ <option name="mainline-module-package-name" value="com.android.art" />
+ </object>
</configuration>
diff --git a/tests/media/Android.bp b/tests/media/Android.bp
index d78e2b7..81c56af 100644
--- a/tests/media/Android.bp
+++ b/tests/media/Android.bp
@@ -42,6 +42,7 @@
test_suites: [
"cts",
"general-tests",
+ "mts-media",
],
min_sdk_version: "29",
}
diff --git a/tests/media/AndroidTest.xml b/tests/media/AndroidTest.xml
index 872e8b1..061a609 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-1.10" />
+ <option name="media-folder-name" value="CtsMediaV2TestCases-1.12" />
<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 5ad3c66..75dfad3 100644
--- a/tests/media/DynamicConfig.xml
+++ b/tests/media/DynamicConfig.xml
@@ -1,6 +1,5 @@
<dynamicConfig>
<entry key="media_files_url">
- <value>https://storage.googleapis.com/android_media/cts/tests/media/CtsMediaV2TestCases-1.10.zip</value>
+ <value>https://storage.googleapis.com/android_media/cts/tests/media/CtsMediaV2TestCases-1.12.zip</value>
</entry>
</dynamicConfig>
-
diff --git a/tests/media/README.md b/tests/media/README.md
index 54de250..fb10920 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-1.10.zip) and is downloaded automatically while running tests. Manual installation of these can be done using install_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-1.12.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 suite looks to cover sdk/ndk api in normal and error scenarios. Error scenarios are separated from regular usage and are placed under class *UnitTest (MuxerUnitTest, ExtractorUnitTest, ...).
@@ -16,12 +16,48 @@
```
### Features
-All tests accepts attributes that offer selective run of tests. Media codec tests parses the value of key *codec-sel* to determine the list of components on which the tests are to be tried. Similarly for Media extractor and media muxer parses the value of keys *ext-sel* and *mux-sel* to determine the list of components on which the tests are to be tried.
+All tests accepts attributes that offer selective run of tests.
-To limit media codec decoder tests to mp3 and vorbis decoder,
+#### Select codecs by name
+To select codecs by name, *codec-prefix* can be passed to media codec tests to select one or more codecs that start with a given prefix.
+
+Example: To limit the tests to run for codecs whose names start with c2.android.
+
```sh
-adb shell am instrument -w -r -e codec-sel 'mp3;vorbis' -e debug false -e class 'android.mediav2.cts.CodecDecoderTest' android.mediav2.cts.test/androidx.test.runner.AndroidJUnitRunner
+atest CtsMediaV2TestCases -- --module-arg CtsMediaV2TestCases:instrumentation-arg:codec-prefix:=c2.android.
```
+
+Example: To limit the tests to run for c2.android.hevc.decoder
+
+```sh
+atest CtsMediaV2TestCases -- --module-arg CtsMediaV2TestCases:instrumentation-arg:codec-prefix:=c2.android.hevc.decoder
+```
+
+#### Select codecs by type
+To select codecs by type, *mime-sel* can be passed to media codec tests to select one or more codecs.
+
+Example: To limit media codec decoder tests to mp3 and vorbis decoder
+
+```sh
+atest android.mediav2.cts.CodecDecoderTest -- --module-arg CtsMediaV2TestCases:instrumentation-arg:mime-sel:=mp3,vorbis
+```
+
+#### Select extractors by type
+To select extractors by type, *ext-sel* can be passed to extractor tests to select one or more extractors.
+
+Example: To limit extractor tests to mp4 and webm types
+```sh
+atest android.mediav2.cts.ExtractorTest -- --module-arg CtsMediaV2TestCases:instrumentation-arg:ext-sel:=mp4,webm
+```
+
+#### Select muxers by type
+To select muxers by type, *mux-sel* can be passed to muxer tests to select one or more muxers.
+
+Example: To limit muxer tests to mp4 and webm types
+```sh
+atest android.mediav2.cts.MuxerTest -- --module-arg CtsMediaV2TestCases:instrumentation-arg:mux-sel:=mp4,webm
+```
+
### Appendix
| Identifier for codec-sel | Mime |
| ------ | ------ |
diff --git a/tests/media/copy_media.sh b/tests/media/copy_media.sh
index 9e6b741..3bfd4b3 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-1.10
+resLabel=CtsMediaV2TestCases-1.12
srcDir="/tmp/$resLabel"
tgtDir="/sdcard/test"
usage="Usage: $0 [-h] [-s serial]"
diff --git a/tests/media/jni/NativeCodecDecoderTest.cpp b/tests/media/jni/NativeCodecDecoderTest.cpp
index 0b17d7e..d68a040 100644
--- a/tests/media/jni/NativeCodecDecoderTest.cpp
+++ b/tests/media/jni/NativeCodecDecoderTest.cpp
@@ -388,10 +388,12 @@
}
if (mSaveToMem && refFile && rmsError >= 0) {
setUpAudioReference(refFile);
- float error = ref->getRmsError(mRefData, mRefLength);
- if (error > rmsError) {
+ float currError = ref->getRmsError(mRefData, mRefLength);
+ float errMargin = rmsError * kRmsErrorTolerance;
+ if (currError > errMargin) {
isPass = false;
- ALOGE("rms error too high for file %s, act/exp: %f/%f", testFile, error, rmsError);
+ ALOGE("rms error too high for file %s, ref/exp/got: %f/%f/%f", testFile, rmsError,
+ errMargin, currError);
}
}
return isPass;
diff --git a/tests/media/jni/NativeMediaCommon.cpp b/tests/media/jni/NativeMediaCommon.cpp
index 6d87084..2c7ec7a 100644
--- a/tests/media/jni/NativeMediaCommon.cpp
+++ b/tests/media/jni/NativeMediaCommon.cpp
@@ -46,6 +46,9 @@
const char* TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES = "max-bframes";
const char* TBD_AMEDIAFORMAT_KEY_BIT_RATE_MODE = "bitrate-mode";
+// NDK counterpart of RMS_ERROR_TOLERANCE of CodecDecoderTest class
+const float kRmsErrorTolerance = 1.05f;
+
// NDK counterpart of Q_DEQ_TIMEOUT_US and RETRY_LIMIT of CodecTestBase class
const long kQDeQTimeOutUs = 5000; // block at most 5ms while looking for io buffers
const int kRetryLimit = 100; // max poll counter before test aborts and returns error
diff --git a/tests/media/jni/NativeMediaCommon.h b/tests/media/jni/NativeMediaCommon.h
index 9db5af0..e8f83f6 100644
--- a/tests/media/jni/NativeMediaCommon.h
+++ b/tests/media/jni/NativeMediaCommon.h
@@ -35,6 +35,8 @@
extern const char* AMEDIA_MIMETYPE_AUDIO_VORBIS;
extern const char* AMEDIA_MIMETYPE_AUDIO_OPUS;
+extern const float kRmsErrorTolerance;
+
extern const long kQDeQTimeOutUs;
extern const int kRetryLimit;
diff --git a/tests/media/src/android/mediav2/cts/AdaptivePlaybackTest.java b/tests/media/src/android/mediav2/cts/AdaptivePlaybackTest.java
new file mode 100644
index 0000000..f95fa54
--- /dev/null
+++ b/tests/media/src/android/mediav2/cts/AdaptivePlaybackTest.java
@@ -0,0 +1,226 @@
+/*
+ * 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.mediav2.cts;
+
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+
+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.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import static org.junit.Assert.fail;
+
+@RunWith(Parameterized.class)
+public class AdaptivePlaybackTest extends CodecDecoderTestBase {
+ private final String mMime;
+ private final String[] mSrcFiles;
+ private final int mSupport;
+
+ private long mMaxPts = 0;
+
+ public AdaptivePlaybackTest(String mime, String[] srcFiles, int support) {
+ super(mime, null);
+ mMime = mime;
+ mSrcFiles = srcFiles;
+ mSupport = support;
+ }
+
+ @Rule
+ public ActivityTestRule<CodecTestActivity> mActivityRule =
+ new ActivityTestRule<>(CodecTestActivity.class);
+
+ @Parameterized.Parameters(name = "{index}({0})")
+ public static Collection<Object[]> input() {
+ final boolean isEncoder = false;
+ final boolean needAudio = false;
+ final boolean needVideo = true;
+ // mime, array list of test files we'll play, codec should support adaptive feature
+ final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
+ {MediaFormat.MIMETYPE_VIDEO_AVC, new String[]{
+ "bbb_800x640_768kbps_30fps_avc_2b.mp4",
+ "bbb_800x640_768kbps_30fps_avc_nob.mp4",
+ "bbb_1280x720_1mbps_30fps_avc_2b.mp4",
+ "bbb_640x360_512kbps_30fps_avc_nob.mp4",
+ "bbb_1280x720_1mbps_30fps_avc_nob.mp4",
+ "bbb_640x360_512kbps_30fps_avc_2b.mp4",
+ "bbb_1280x720_1mbps_30fps_avc_nob.mp4",
+ "bbb_640x360_512kbps_30fps_avc_nob.mp4",
+ "bbb_640x360_512kbps_30fps_avc_2b.mp4"}, CODEC_ALL},
+ {MediaFormat.MIMETYPE_VIDEO_HEVC, new String[]{
+ "bbb_800x640_768kbps_30fps_hevc_2b.mp4",
+ "bbb_800x640_768kbps_30fps_hevc_nob.mp4",
+ "bbb_1280x720_1mbps_30fps_hevc_2b.mp4",
+ "bbb_640x360_512kbps_30fps_hevc_nob.mp4",
+ "bbb_1280x720_1mbps_30fps_hevc_nob.mp4",
+ "bbb_640x360_512kbps_30fps_hevc_2b.mp4",
+ "bbb_1280x720_1mbps_30fps_hevc_nob.mp4",
+ "bbb_640x360_512kbps_30fps_hevc_nob.mp4",
+ "bbb_640x360_512kbps_30fps_hevc_2b.mp4"}, CODEC_ALL},
+ {MediaFormat.MIMETYPE_VIDEO_VP8, new String[]{
+ "bbb_800x640_768kbps_30fps_vp8.webm",
+ "bbb_1280x720_1mbps_30fps_vp8.webm",
+ "bbb_640x360_512kbps_30fps_vp8.webm"}, CODEC_ALL},
+ {MediaFormat.MIMETYPE_VIDEO_VP9, new String[]{
+ "bbb_800x640_768kbps_30fps_vp9.webm",
+ "bbb_1280x720_1mbps_30fps_vp9.webm",
+ "bbb_640x360_512kbps_30fps_vp9.webm"}, CODEC_ALL},
+ {MediaFormat.MIMETYPE_VIDEO_MPEG4, new String[]{
+ "bbb_128x96_64kbps_12fps_mpeg4.mp4",
+ "bbb_176x144_192kbps_15fps_mpeg4.mp4",
+ "bbb_128x96_64kbps_12fps_mpeg4.mp4"}, CODEC_ALL},
+ {MediaFormat.MIMETYPE_VIDEO_AV1, new String[]{
+ "bbb_800x640_768kbps_30fps_av1.webm",
+ "bbb_1280x720_1mbps_30fps_av1.webm",
+ "bbb_640x360_512kbps_30fps_av1.webm"}, CODEC_ALL},
+ {MediaFormat.MIMETYPE_VIDEO_MPEG2, new String[]{
+ "bbb_800x640_768kbps_30fps_mpeg2_2b.mp4",
+ "bbb_800x640_768kbps_30fps_mpeg2_nob.mp4",
+ "bbb_1280x720_1mbps_30fps_mpeg2_2b.mp4",
+ "bbb_640x360_512kbps_30fps_mpeg2_nob.mp4",
+ "bbb_1280x720_1mbps_30fps_mpeg2_nob.mp4",
+ "bbb_640x360_512kbps_30fps_mpeg2_2b.mp4",
+ "bbb_1280x720_1mbps_30fps_mpeg2_nob.mp4",
+ "bbb_640x360_512kbps_30fps_mpeg2_nob.mp4",
+ "bbb_640x360_512kbps_30fps_mpeg2_2b.mp4"}, CODEC_ALL},
+ });
+ return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, false);
+ }
+
+ @Override
+ void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ mSawOutputEOS = true;
+ }
+ if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+ mOutputBuff.saveOutPTS(info.presentationTimeUs);
+ mOutputCount++;
+ }
+ mCodec.releaseOutputBuffer(bufferIndex, mSurface != null);
+ }
+
+ private MediaFormat createInputList(MediaFormat format, ByteBuffer buffer,
+ ArrayList<MediaCodec.BufferInfo> list, int offset, long ptsOffset) {
+ if (hasCSD(format)) {
+ MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
+ bufferInfo.offset = offset;
+ bufferInfo.size = 0;
+ bufferInfo.presentationTimeUs = 0;
+ bufferInfo.flags = MediaCodec.BUFFER_FLAG_CODEC_CONFIG;
+ for (int i = 0; ; i++) {
+ String csdKey = "csd-" + i;
+ if (format.containsKey(csdKey)) {
+ ByteBuffer csdBuffer = format.getByteBuffer(csdKey);
+ bufferInfo.size += csdBuffer.limit();
+ buffer.put(csdBuffer);
+ format.removeKey(csdKey);
+ } else break;
+ }
+ list.add(bufferInfo);
+ offset += bufferInfo.size;
+ }
+ while (true) {
+ MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
+ bufferInfo.size = mExtractor.readSampleData(buffer, offset);
+ if (bufferInfo.size < 0) break;
+ bufferInfo.offset = offset;
+ bufferInfo.presentationTimeUs = ptsOffset + mExtractor.getSampleTime();
+ mMaxPts = Math.max(mMaxPts, bufferInfo.presentationTimeUs);
+ int flags = mExtractor.getSampleFlags();
+ bufferInfo.flags = 0;
+ if ((flags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
+ bufferInfo.flags |= MediaCodec.BUFFER_FLAG_KEY_FRAME;
+ }
+ list.add(bufferInfo);
+ mExtractor.advance();
+ offset += bufferInfo.size;
+ }
+ buffer.clear();
+ buffer.position(offset);
+ return format;
+ }
+
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ public void testAdaptivePlayback() throws IOException, InterruptedException {
+ CodecTestActivity activity = mActivityRule.getActivity();
+ setUpSurface(activity);
+ ArrayList<MediaFormat> formats = new ArrayList<>();
+ if (mSupport != CODEC_ALL) {
+ formats = new ArrayList<>();
+ for (String file : mSrcFiles) {
+ formats.add(setUpSource(file));
+ mExtractor.release();
+ }
+ }
+ ArrayList<String> listOfDecoders = selectCodecs(mMime, formats,
+ new String[]{MediaCodecInfo.CodecCapabilities.FEATURE_AdaptivePlayback}, false);
+ if (listOfDecoders.isEmpty()) {
+ tearDownSurface();
+ if (mSupport == CODEC_OPTIONAL) return;
+ else fail("no suitable codecs found for mime: " + mMime);
+ }
+ formats.clear();
+ int totalSize = 0;
+ for (String srcFile : mSrcFiles) {
+ File file = new File(mInpPrefix + srcFile);
+ totalSize += (int) file.length();
+ }
+ totalSize <<= 1;
+ long ptsOffset = 0;
+ int buffOffset = 0;
+ ArrayList<MediaCodec.BufferInfo> list = new ArrayList<>();
+ ByteBuffer buffer = ByteBuffer.allocate(totalSize);
+ for (String file : mSrcFiles) {
+ formats.add(createInputList(setUpSource(file), buffer, list, buffOffset, ptsOffset));
+ mExtractor.release();
+ ptsOffset = mMaxPts + 1000000L;
+ buffOffset = (list.get(list.size() - 1).offset) + (list.get(list.size() - 1).size);
+ }
+ boolean[] boolStates = {false, true};
+ mOutputBuff = new OutputManager();
+ for (String decoder : listOfDecoders) {
+ mCodec = MediaCodec.createByCodecName(decoder);
+ MediaFormat format = formats.get(0);
+ activity.setScreenParams(getWidth(format), getHeight(format), true);
+ for (boolean isAsync : boolStates) {
+ mOutputBuff.reset();
+ configureCodec(format, isAsync, false, false);
+ mCodec.start();
+ doWork(buffer, list);
+ queueEOS();
+ waitForAllOutputs();
+ mCodec.reset();
+ }
+ }
+ tearDownSurface();
+ }
+}
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderPauseTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderPauseTest.java
new file mode 100644
index 0000000..f07dbfd
--- /dev/null
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderPauseTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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.mediav2.cts;
+
+import android.media.MediaCodec;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+
+import androidx.test.filters.LargeTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * The following test validates that the decode can be paused
+ */
+@RunWith(Parameterized.class)
+public class CodecDecoderPauseTest extends CodecDecoderTestBase {
+ private static final String LOG_TAG = CodecDecoderPauseTest.class.getSimpleName();
+ private final long PAUSE_TIME_MS = 10000;
+ private final int NUM_FRAMES = 8;
+ private final int mSupport;
+
+ public CodecDecoderPauseTest(String mime, String srcFile, int support) {
+ super(mime, srcFile);
+ mSupport = support;
+ }
+
+ @Parameterized.Parameters(name = "{index}({0})")
+ public static Collection<Object[]> input() {
+ final boolean isEncoder = false;
+ final boolean needAudio = true;
+ final boolean needVideo = true;
+ // mime, source file, codecs required to support
+ final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
+ {MediaFormat.MIMETYPE_AUDIO_AAC, "bbb_2ch_48kHz_he_aac.mp4", CODEC_ALL},
+ {MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_cif_avc_delay16.mp4", CODEC_ALL},
+ {MediaFormat.MIMETYPE_VIDEO_H263, "bbb_cif_768kbps_30fps_h263.mp4", CODEC_ALL},
+ {MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_cif_hevc_delay15.mp4", CODEC_ALL},
+ {MediaFormat.MIMETYPE_VIDEO_MPEG2, "bbb_640x360_512kbps_30fps_mpeg2_2b.mp4", CODEC_ALL},
+ {MediaFormat.MIMETYPE_VIDEO_MPEG4, "bbb_176x144_192kbps_15fps_mpeg4.mp4", CODEC_ALL},
+ {MediaFormat.MIMETYPE_VIDEO_VP8, "bbb_640x360_512kbps_30fps_vp8.webm", CODEC_ALL},
+ {MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_cif_768kbps_30fps_vp9.mkv", CODEC_ALL},
+ });
+ return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, false);
+ }
+
+ /**
+ * Test decodes and compares decoded output of two files.
+ */
+ @LargeTest
+ @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ public void testPause() throws IOException, InterruptedException {
+ ArrayList<MediaFormat> formats = null;
+ if (mSupport != CODEC_ALL) {
+ formats = new ArrayList<>();
+ formats.add(setUpSource(mTestFile));
+ mExtractor.release();
+ }
+ ArrayList<String> listOfDecoders = selectCodecs(mMime, formats, null, false);
+ if (listOfDecoders.isEmpty()) {
+ if (mSupport == CODEC_OPTIONAL) return;
+ else fail("no suitable codecs found for mime: " + mMime);
+ }
+ final boolean isAsync = true;
+ MediaFormat format = setUpSource(mTestFile);
+ for (String decoder : listOfDecoders) {
+ mCodec = MediaCodec.createByCodecName(decoder);
+ int loopCounter = 0;
+ boolean[] boolStates = {true, false};
+ OutputManager ref = new OutputManager();
+ OutputManager test = new OutputManager();
+ for (boolean enablePause : boolStates) {
+ String log = String.format("decoder: %s, input file: %s, mode: %s:: ", decoder,
+ mTestFile, (isAsync ? "async" : "sync"));
+ mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+ configureCodec(format, isAsync, false, false);
+ mOutputBuff = loopCounter == 0 ? ref : test;
+ mOutputBuff.reset();
+ mCodec.start();
+ if (enablePause) {
+ doWork(NUM_FRAMES);
+ Thread.sleep(PAUSE_TIME_MS);
+ }
+ doWork(Integer.MAX_VALUE);
+ queueEOS();
+ waitForAllOutputs();
+ mCodec.reset();
+ assertTrue(log + " unexpected error", !mAsyncHandle.hasSeenError());
+ if (loopCounter != 0) {
+ assertTrue(log + "decoder output is flaky", ref.equals(test));
+ } else {
+ if (mIsAudio) {
+ assertTrue(log + " pts is not strictly increasing",
+ ref.isPtsStrictlyIncreasing(mPrevOutputPts));
+ } else {
+ assertTrue(log + " input pts list and output pts list are not identical",
+ ref.isOutPtsListIdenticalToInpPtsList(false));
+ }
+ }
+ loopCounter++;
+ }
+ mCodec.release();
+ }
+ mExtractor.release();
+ }
+}
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
index ad212ff..7e47493 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
@@ -25,6 +25,7 @@
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
+import org.junit.Assume;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
@@ -299,6 +300,8 @@
@LargeTest
@Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
public void testReconfigure() throws IOException, InterruptedException {
+ Assume.assumeTrue("Test needs Android 11", IS_AT_LEAST_R);
+
MediaFormat format = setUpSource(mTestFile);
mExtractor.release();
MediaFormat newFormat = setUpSource(mReconfigFile);
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderTest.java
index 8ba5428..dfd79297 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderTest.java
@@ -75,8 +75,8 @@
mRefCRC = refCRC;
}
- private short[] setUpAudioReference() throws IOException {
- File refFile = new File(mInpPrefix + mRefFile);
+ static short[] setUpAudioReference(String file) throws IOException {
+ File refFile = new File(file);
short[] refData;
try (FileInputStream refStream = new FileInputStream(refFile)) {
FileChannel fileChannel = refStream.getChannel();
@@ -184,17 +184,16 @@
private native boolean nativeTestSimpleDecode(String decoder, Surface surface, String mime,
String testFile, String refFile, float rmsError, long checksum);
- private void verify() throws IOException {
- if (mRmsError >= 0) {
- assertTrue(mRefFile != null);
- short[] refData = setUpAudioReference();
- float currError = mOutputBuff.getRmsError(refData);
- float errMargin = mRmsError * RMS_ERROR_TOLERANCE;
- assertTrue(String.format("%s rms error too high exp/got %f/%f", mTestFile,
- errMargin, currError), currError <= errMargin);
- } else if (mRefCRC >= 0) {
- assertEquals(String.format("%s checksum mismatch", mTestFile), mRefCRC,
- mOutputBuff.getCheckSumImage());
+ static void verify(OutputManager outBuff, String refFile, float rmsError, long refCRC)
+ throws IOException {
+ if (rmsError >= 0) {
+ short[] refData = setUpAudioReference(mInpPrefix + refFile);
+ float currError = outBuff.getRmsError(refData);
+ float errMargin = rmsError * RMS_ERROR_TOLERANCE;
+ assertTrue(String.format("%s rms error too high ref/exp/got %f/%f/%f", refFile,
+ rmsError, errMargin, currError), currError <= errMargin);
+ } else if (refCRC >= 0) {
+ assertEquals("checksum mismatch", refCRC, outBuff.getCheckSumImage());
}
}
@@ -281,10 +280,9 @@
}
}
mCodec.release();
- if (mSaveToMem) verify();
+ if (mSaveToMem) verify(mOutputBuff, mRefFile, mRmsError, mRefCRC);
assertTrue(nativeTestSimpleDecode(decoder, null, mMime, mInpPrefix + mTestFile,
- mInpPrefix + mRefFile, mRmsError * RMS_ERROR_TOLERANCE,
- ref.getCheckSumBuffer()));
+ mInpPrefix + mRefFile, mRmsError, ref.getCheckSumBuffer()));
}
mExtractor.release();
}
@@ -429,6 +427,8 @@
@LargeTest
@Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
public void testReconfigure() throws IOException, InterruptedException {
+ Assume.assumeTrue("Test needs Android 11", IS_AT_LEAST_R);
+
MediaFormat format = setUpSource(mTestFile);
mExtractor.release();
MediaFormat newFormat = setUpSource(mReconfigFile);
@@ -506,7 +506,7 @@
doWork(Integer.MAX_VALUE);
queueEOS();
waitForAllOutputs();
- if (mSaveToMem) verify();
+ if (mSaveToMem) verify(mOutputBuff, mRefFile, mRmsError, mRefCRC);
/* TODO(b/147348711) */
if (false) mCodec.stop();
else mCodec.reset();
@@ -532,7 +532,7 @@
doWork(Integer.MAX_VALUE);
queueEOS();
waitForAllOutputs();
- if (mSaveToMem) verify();
+ if (mSaveToMem) verify(mOutputBuff, mRefFile, mRmsError, mRefCRC);
/* TODO(b/147348711) */
if (false) mCodec.stop();
else mCodec.reset();
@@ -672,7 +672,7 @@
for (int i = 0; ; i++) {
String csdKey = "csd-" + i;
if (format.containsKey(csdKey)) {
- mCsdBuffers.add(format.getByteBuffer(csdKey));
+ mCsdBuffers.add(format.getByteBuffer(csdKey).duplicate());
format.removeKey(csdKey);
} else break;
}
@@ -688,7 +688,8 @@
for (String decoder : listOfDecoders) {
mCodec = MediaCodec.createByCodecName(decoder);
int loopCounter = 0;
- for (MediaFormat fmt : formats) {
+ for (int i = 0; i < formats.size(); i++) {
+ MediaFormat fmt = formats.get(i);
for (boolean eosMode : boolStates) {
for (boolean isAsync : boolStates) {
boolean validateFormat = true;
@@ -707,7 +708,7 @@
validateFormat = false;
}
mCodec.start();
- queueCodecConfig();
+ if (i == 0) queueCodecConfig();
doWork(Integer.MAX_VALUE);
queueEOS();
waitForAllOutputs();
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderValidationTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderValidationTest.java
index ba2a3ea..1696561 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderValidationTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderValidationTest.java
@@ -25,18 +25,12 @@
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -51,7 +45,6 @@
@RunWith(Parameterized.class)
public class CodecDecoderValidationTest extends CodecDecoderTestBase {
private static final String LOG_TAG = CodecDecoderValidationTest.class.getSimpleName();
- private static final float RMS_ERROR_TOLERANCE = 1.05f; // 5%
private final String[] mSrcFiles;
private final String mRefFile;
@@ -77,28 +70,39 @@
// mime, array list of test files (underlying elementary stream is same, except they
// are placed in different containers), ref file, rms error, checksum
final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
+ // vp9 test vectors with no-show frames signalled in alternate ways
{MediaFormat.MIMETYPE_VIDEO_VP9, new String[]{
"bbb_340x280_768kbps_30fps_split_non_display_frame_vp9.webm",
"bbb_340x280_768kbps_30fps_vp9.webm"}, null, -1.0f, 4122701060L, CODEC_ALL},
{MediaFormat.MIMETYPE_VIDEO_VP9, new String[]{
"bbb_520x390_1mbps_30fps_split_non_display_frame_vp9.webm",
"bbb_520x390_1mbps_30fps_vp9.webm"}, null, -1.0f, 1201859039L, CODEC_ALL},
+
+ // mpeg2 test vectors with interlaced fields signalled in alternate ways
{MediaFormat.MIMETYPE_VIDEO_MPEG2, new String[]{
"bbb_512x288_30fps_1mbps_mpeg2_interlaced_nob_1field.ts",
"bbb_512x288_30fps_1mbps_mpeg2_interlaced_nob_2fields.mp4"}, null, -1.0f,
-1L, CODEC_ALL},
+
+ // clips with crop parameters
// /* TODO(b/163299340) */
// {MediaFormat.MIMETYPE_VIDEO_HEVC, new String[]{"bbb_560x280_1mbps_30fps_hevc.mkv"},
// null, -1.0f, 26298353L, CODEC_ALL},
// /* TODO(b/163299340) */
// {MediaFormat.MIMETYPE_VIDEO_AVC, new String[]{"bbb_504x224_768kbps_30fps_avc.mp4"},
// null, -1.0f, 4060874918L, CODEC_ALL},
+
+ // misc mp3 test vectors
{MediaFormat.MIMETYPE_AUDIO_MPEG, new String[]{"bbb_1ch_16kHz_lame_vbr.mp3"},
"bbb_1ch_16kHz_s16le.raw", 119.256f, -1L, CODEC_ALL},
{MediaFormat.MIMETYPE_AUDIO_MPEG, new String[]{"bbb_2ch_44kHz_lame_vbr.mp3"},
"bbb_2ch_44kHz_s16le.raw", 53.066f, -1L, CODEC_ALL},
+
+ // mp3 test vectors with CRC
{MediaFormat.MIMETYPE_AUDIO_MPEG, new String[]{"bbb_2ch_44kHz_lame_crc.mp3"},
"bbb_2ch_44kHz_s16le.raw", 104.09f, -1L, CODEC_ALL},
+
+ // vp9 test vectors with AQ mode enabled
{MediaFormat.MIMETYPE_VIDEO_VP9, new String[]{"bbb_1280x720_800kbps_30fps_vp9" +
".webm"}, null, -1.0f, 1319105122L, CODEC_ALL},
{MediaFormat.MIMETYPE_VIDEO_VP9, new String[]{"bbb_1280x720_1200kbps_30fps_vp9" +
@@ -107,41 +111,355 @@
".webm"}, null, -1.0f, 156928091L, CODEC_ALL},
{MediaFormat.MIMETYPE_VIDEO_VP9, new String[]{"bbb_1280x720_2000kbps_30fps_vp9" +
".webm"}, null, -1.0f, 3902485256L, CODEC_ALL},
+
+ // video test vectors of non standard sizes
+ {MediaFormat.MIMETYPE_VIDEO_MPEG2, new String[]{
+ "bbb_642x642_2mbps_30fps_mpeg2.mp4"}, null, -1.0f, -1L, CODEC_ANY},
+ {MediaFormat.MIMETYPE_VIDEO_AVC, new String[]{
+ "bbb_642x642_1mbps_30fps_avc.mp4"}, null, -1.0f, 3947092788L, CODEC_ANY},
+ {MediaFormat.MIMETYPE_VIDEO_VP8, new String[]{
+ "bbb_642x642_1mbps_30fps_vp8.webm"}, null, -1.0f, 516982978L, CODEC_ANY},
+ {MediaFormat.MIMETYPE_VIDEO_HEVC, new String[]{
+ "bbb_642x642_768kbps_30fps_hevc.mp4"}, null, -1.0f, 3018465268L, CODEC_ANY},
+ {MediaFormat.MIMETYPE_VIDEO_VP9, new String[]{
+ "bbb_642x642_768kbps_30fps_vp9.webm"}, null, -1.0f, 4032809269L, CODEC_ANY},
+ {MediaFormat.MIMETYPE_VIDEO_AV1, new String[]{
+ "bbb_642x642_768kbps_30fps_av1.mp4"}, null, -1.0f, 3684481474L, CODEC_ANY},
+ {MediaFormat.MIMETYPE_VIDEO_MPEG4, new String[]{
+ "bbb_130x130_192kbps_15fps_mpeg4.mp4"}, null, -1.0f, -1L, CODEC_ANY},
+
+ // audio test vectors covering cdd sec 5.1.3
+ // amr nb
+ {MediaFormat.MIMETYPE_AUDIO_AMR_NB, new String[]{
+ "audio/bbb_mono_8kHz_12.2kbps_amrnb.3gp"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AMR_NB, new String[]{
+ "audio/bbb_mono_8kHz_10.2kbps_amrnb.3gp"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AMR_NB, new String[]{
+ "audio/bbb_mono_8kHz_7.95kbps_amrnb.3gp"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AMR_NB, new String[]{
+ "audio/bbb_mono_8kHz_7.40kbps_amrnb.3gp"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AMR_NB, new String[]{
+ "audio/bbb_mono_8kHz_6.70kbps_amrnb.3gp"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AMR_NB, new String[]{
+ "audio/bbb_mono_8kHz_5.90kbps_amrnb.3gp"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AMR_NB, new String[]{
+ "audio/bbb_mono_8kHz_5.15kbps_amrnb.3gp"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AMR_NB, new String[]{
+ "audio/bbb_mono_8kHz_4.75kbps_amrnb.3gp"}, null, -1.0f, -1L, CODEC_ALL},
+
+ // amr wb
+ {MediaFormat.MIMETYPE_AUDIO_AMR_WB, new String[]{
+ "audio/bbb_mono_16kHz_6.6kbps_amrwb.3gp"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AMR_WB, new String[]{
+ "audio/bbb_mono_16kHz_8.85kbps_amrwb.3gp"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AMR_WB, new String[]{
+ "audio/bbb_mono_16kHz_12.65kbps_amrwb.3gp"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AMR_WB, new String[]{
+ "audio/bbb_mono_16kHz_14.25kbps_amrwb.3gp"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AMR_WB, new String[]{
+ "audio/bbb_mono_16kHz_15.85kbps_amrwb.3gp"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AMR_WB, new String[]{
+ "audio/bbb_mono_16kHz_18.25kbps_amrwb.3gp"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AMR_WB, new String[]{
+ "audio/bbb_mono_16kHz_19.85kbps_amrwb.3gp"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AMR_WB, new String[]{
+ "audio/bbb_mono_16kHz_23.05kbps_amrwb.3gp"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AMR_WB, new String[]{
+ "audio/bbb_mono_16kHz_23.85kbps_amrwb.3gp"}, null, -1.0f, -1L, CODEC_ALL},
+
+ // flac
+ // TODO(add content for 96kHz and 192kHz)
+ {MediaFormat.MIMETYPE_AUDIO_FLAC, new String[]{"audio/bbb_1ch_8kHz_lvl4_flac.mka"},
+ "audio/bbb_1ch_8kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_FLAC, new String[]{"audio/bbb_1ch_12kHz_lvl4_flac.mka"},
+ "audio/bbb_1ch_12kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_FLAC, new String[]{"audio/bbb_1ch_16kHz_lvl4_flac.mka"},
+ "audio/bbb_1ch_16kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_FLAC, new String[]{"audio/bbb_1ch_22kHz_lvl4_flac.mka"},
+ "audio/bbb_1ch_22kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_FLAC, new String[]{"audio/bbb_1ch_24kHz_lvl4_flac.mka"},
+ "audio/bbb_1ch_24kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_FLAC, new String[]{"audio/bbb_1ch_32kHz_lvl4_flac.mka"},
+ "audio/bbb_1ch_32kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_FLAC, new String[]{"audio/bbb_1ch_44kHz_lvl4_flac.mka"},
+ "audio/bbb_1ch_44kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_FLAC, new String[]{"audio/bbb_1ch_48kHz_lvl4_flac.mka"},
+ "audio/bbb_1ch_48kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_FLAC, new String[]{"audio/bbb_2ch_8kHz_lvl4_flac.mka"},
+ "audio/bbb_2ch_8kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_FLAC, new String[]{"audio/bbb_2ch_12kHz_lvl4_flac.mka"},
+ "audio/bbb_2ch_12kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_FLAC, new String[]{"audio/bbb_2ch_16kHz_lvl4_flac.mka"},
+ "audio/bbb_2ch_16kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_FLAC, new String[]{"audio/bbb_2ch_22kHz_lvl4_flac.mka"},
+ "audio/bbb_2ch_22kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_FLAC, new String[]{"audio/bbb_2ch_24kHz_lvl4_flac.mka"},
+ "audio/bbb_2ch_24kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_FLAC, new String[]{"audio/bbb_2ch_32kHz_lvl4_flac.mka"},
+ "audio/bbb_2ch_32kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_FLAC, new String[]{"audio/bbb_2ch_44kHz_lvl4_flac.mka"},
+ "audio/bbb_2ch_44kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_FLAC, new String[]{"audio/bbb_2ch_48kHz_lvl4_flac.mka"},
+ "audio/bbb_2ch_48kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+
+ // opus
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_1ch_8kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_1ch_12kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_1ch_16kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_1ch_24kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_1ch_32kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_1ch_48kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_2ch_8kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_2ch_12kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_2ch_16kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_2ch_24kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_2ch_32kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_2ch_48kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_5ch_8kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_5ch_12kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_5ch_16kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_5ch_24kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_5ch_32kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_5ch_48kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_6ch_8kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_6ch_12kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_6ch_16kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_6ch_24kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_6ch_32kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_OPUS, new String[]{
+ "audio/bbb_6ch_48kHz_opus.ogg"}, null, -1.0f, -1L, CODEC_ALL},
+
+ // raw
+ // TODO: add content for larger sampling rates and float pcm
+ {MediaFormat.MIMETYPE_AUDIO_RAW, new String[]{"audio/bbb_1ch_8kHz.wav"},
+ "audio/bbb_1ch_8kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_RAW, new String[]{"audio/bbb_1ch_16kHz.wav"},
+ "audio/bbb_1ch_16kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_RAW, new String[]{"audio/bbb_1ch_22kHz.wav"},
+ "audio/bbb_1ch_22kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_RAW, new String[]{"audio/bbb_1ch_24kHz.wav"},
+ "audio/bbb_1ch_24kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_RAW, new String[]{"audio/bbb_1ch_32kHz.wav"},
+ "audio/bbb_1ch_32kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_RAW, new String[]{"audio/bbb_1ch_44kHz.wav"},
+ "audio/bbb_1ch_44kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_RAW, new String[]{"audio/bbb_1ch_48kHz.wav"},
+ "audio/bbb_1ch_48kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_RAW, new String[]{"audio/bbb_2ch_8kHz.wav"},
+ "audio/bbb_2ch_8kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_RAW, new String[]{"audio/bbb_2ch_16kHz.wav"},
+ "audio/bbb_2ch_16kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_RAW, new String[]{"audio/bbb_2ch_22kHz.wav"},
+ "audio/bbb_2ch_22kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_RAW, new String[]{"audio/bbb_2ch_24kHz.wav"},
+ "audio/bbb_2ch_24kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_RAW, new String[]{"audio/bbb_2ch_32kHz.wav"},
+ "audio/bbb_2ch_32kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_RAW, new String[]{"audio/bbb_2ch_44kHz.wav"},
+ "audio/bbb_2ch_44kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_RAW, new String[]{"audio/bbb_2ch_48kHz.wav"},
+ "audio/bbb_2ch_48kHz_s16le_3s.raw", 0.0f, -1L, CODEC_ALL},
+
+ // aac-lc
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_8kHz_aac_lc.m4a"},
+ "audio/bbb_1ch_8kHz_s16le_3s.raw", 26.907248f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_12kHz_aac_lc.m4a"},
+ "audio/bbb_1ch_12kHz_s16le_3s.raw", 23.366642f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_16kHz_aac_lc.m4a"},
+ "audio/bbb_1ch_16kHz_s16le_3s.raw", 21.354156f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_22kHz_aac_lc.m4a"},
+ "audio/bbb_1ch_22kHz_s16le_3s.raw", 25.980762f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_24kHz_aac_lc.m4a"},
+ "audio/bbb_1ch_24kHz_s16le_3s.raw", 26.362852f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_32kHz_aac_lc.m4a"},
+ "audio/bbb_1ch_32kHz_s16le_3s.raw", 28.635643f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_44kHz_aac_lc.m4a"},
+ "audio/bbb_1ch_44kHz_s16le_3s.raw", 29.291637f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_48kHz_aac_lc.m4a"},
+ "audio/bbb_1ch_48kHz_s16le_3s.raw", 29.325756f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_8kHz_aac_lc.m4a"},
+ "audio/bbb_2ch_8kHz_s16le_3s.raw", 26.362852f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_12kHz_aac_lc.m4a"},
+ "audio/bbb_2ch_12kHz_s16le_3s.raw", 21.931713f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_16kHz_aac_lc.m4a"},
+ "audio/bbb_2ch_16kHz_s16le_3s.raw", 22.068077f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_22kHz_aac_lc.m4a"},
+ "audio/bbb_2ch_22kHz_s16le_3s.raw", 25.317978f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_24kHz_aac_lc.m4a"},
+ "audio/bbb_2ch_24kHz_s16le_3s.raw", 25.651510f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_32kHz_aac_lc.m4a"},
+ "audio/bbb_2ch_32kHz_s16le_3s.raw", 27.294687f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_44kHz_aac_lc.m4a"},
+ "audio/bbb_2ch_44kHz_s16le_3s.raw", 27.313000f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_48kHz_aac_lc.m4a"},
+ "audio/bbb_2ch_48kHz_s16le_3s.raw", 27.676704f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_5ch_8kHz_aac_lc.m4a"},
+ "audio/bbb_5ch_8kHz_s16le_3s.raw", 43.116123f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_5ch_12kHz_aac_lc.m4a"},
+ "audio/bbb_5ch_12kHz_s16le_3s.raw", 35.972210f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_5ch_16kHz_aac_lc.m4a"},
+ "audio/bbb_5ch_16kHz_s16le_3s.raw", 32.710854f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_5ch_22kHz_aac_lc.m4a"},
+ "audio/bbb_5ch_22kHz_s16le_3s.raw", 39.281040f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_5ch_24kHz_aac_lc.m4a"},
+ "audio/bbb_5ch_24kHz_s16le_3s.raw", 40.951191f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_5ch_32kHz_aac_lc.m4a"},
+ "audio/bbb_5ch_32kHz_s16le_3s.raw", 49.436829f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_5ch_44kHz_aac_lc.m4a"},
+ "audio/bbb_5ch_44kHz_s16le_3s.raw", 43.886215f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_5ch_48kHz_aac_lc.m4a"},
+ "audio/bbb_5ch_48kHz_s16le_3s.raw", 44.271889f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_6ch_8kHz_aac_lc.m4a"},
+ "audio/bbb_6ch_8kHz_s16le_3s.raw", 39.661064f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_6ch_12kHz_aac_lc.m4a"},
+ "audio/bbb_6ch_12kHz_s16le_3s.raw", 34.971416f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_6ch_16kHz_aac_lc.m4a"},
+ "audio/bbb_6ch_16kHz_s16le_3s.raw", 29.068884f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_6ch_22kHz_aac_lc.m4a"},
+ "audio/bbb_6ch_22kHz_s16le_3s.raw", 29.427877f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_6ch_24kHz_aac_lc.m4a"},
+ "audio/bbb_6ch_24kHz_s16le_3s.raw", 30.331501f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_6ch_32kHz_aac_lc.m4a"},
+ "audio/bbb_6ch_32kHz_s16le_3s.raw", 33.926392f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_6ch_44kHz_aac_lc.m4a"},
+ "audio/bbb_6ch_44kHz_s16le_3s.raw", 31.733263f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_6ch_48kHz_aac_lc.m4a"},
+ "audio/bbb_6ch_48kHz_s16le_3s.raw", 31.032242f, -1L, CODEC_ALL},
+
+ // aac-he
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_2ch_16kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_2ch_22kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_2ch_24kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_2ch_32kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_2ch_44kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_2ch_48kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_5ch_16kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_5ch_22kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_5ch_24kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_5ch_32kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_5ch_44kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_5ch_48kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_6ch_16kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_6ch_22kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_6ch_24kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_6ch_32kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_6ch_44kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_6ch_48kHz_aac_he.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+
+ // aac-eld
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_16kHz_aac_eld.m4a"},
+ "audio/bbb_1ch_16kHz_s16le_3s.raw", -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_22kHz_aac_eld.m4a"},
+ "audio/bbb_1ch_22kHz_s16le_3s.raw", 24.959969f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_24kHz_aac_eld.m4a"},
+ "audio/bbb_1ch_24kHz_s16le_3s.raw", 26.495283f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_32kHz_aac_eld.m4a"},
+ "audio/bbb_1ch_32kHz_s16le_3s.raw", 31.464266f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_44kHz_aac_eld.m4a"},
+ "audio/bbb_1ch_44kHz_s16le_3s.raw", 33.852623f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_48kHz_aac_eld.m4a"},
+ "audio/bbb_1ch_48kHz_s16le_3s.raw", 33.136082f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_16kHz_aac_eld.m4a"},
+ "audio/bbb_2ch_16kHz_s16le_3s.raw", -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_22kHz_aac_eld.m4a"},
+ "audio/bbb_2ch_22kHz_s16le_3s.raw", 24.959969f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_24kHz_aac_eld.m4a"},
+ "audio/bbb_2ch_24kHz_s16le_3s.raw", 26.962938f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_32kHz_aac_eld.m4a"},
+ "audio/bbb_2ch_32kHz_s16le_3s.raw", 27.784887f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_44kHz_aac_eld.m4a"},
+ "audio/bbb_2ch_44kHz_s16le_3s.raw", 29.223278f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_48kHz_aac_eld.m4a"},
+ "audio/bbb_2ch_48kHz_s16le_3s.raw", 29.171904f, -1L, CODEC_ALL},
+
+ // aac-hev2
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_2ch_16kHz_aac_hev2.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_2ch_22kHz_aac_hev2.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_2ch_24kHz_aac_hev2.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_2ch_32kHz_aac_hev2.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_2ch_44kHz_aac_hev2.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{
+ "audio/bbb_2ch_48kHz_aac_hev2.m4a"}, null, -1.0f, -1L, CODEC_ALL},
+
+ // aac-usac
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_8kHz_usac.m4a"},
+ null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_16kHz_usac.m4a"},
+ null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_22kHz_usac.m4a"},
+ null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_24kHz_usac.m4a"},
+ null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_32kHz_usac.m4a"},
+ null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_44kHz_usac.m4a"},
+ null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_1ch_48kHz_usac.m4a"},
+ null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_8kHz_usac.m4a"},
+ null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_16kHz_usac.m4a"},
+ null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_22kHz_usac.m4a"},
+ null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_24kHz_usac.m4a"},
+ null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_32kHz_usac.m4a"},
+ null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_44kHz_usac.m4a"},
+ null, -1.0f, -1L, CODEC_ALL},
+ {MediaFormat.MIMETYPE_AUDIO_AAC, new String[]{"audio/bbb_2ch_48kHz_usac.m4a"},
+ null, -1.0f, -1L, CODEC_ALL},
});
return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, false);
}
- private short[] setUpAudioReference() throws IOException {
- File refFile = new File(mInpPrefix + mRefFile);
- short[] refData;
- try (FileInputStream refStream = new FileInputStream(refFile)) {
- FileChannel fileChannel = refStream.getChannel();
- int length = (int) refFile.length();
- ByteBuffer refBuffer = ByteBuffer.allocate(length);
- refBuffer.order(ByteOrder.LITTLE_ENDIAN);
- fileChannel.read(refBuffer);
- refData = new short[length / 2];
- refBuffer.position(0);
- for (int i = 0; i < length / 2; i++) {
- refData[i] = refBuffer.getShort();
- }
- }
- return refData;
- }
-
- private void verify() throws IOException {
- if (mRmsError >= 0) {
- assertTrue(mRefFile != null);
- short[] refData = setUpAudioReference();
- float currError = mOutputBuff.getRmsError(refData);
- float errMargin = mRmsError * RMS_ERROR_TOLERANCE;
- assertTrue(String.format("rms error too high exp/got %f/%f", errMargin, currError),
- currError <= errMargin);
- } else if (mRefCRC >= 0) {
- assertEquals("checksum mismatch", mRefCRC, mOutputBuff.getCheckSumImage());
- }
- }
-
/**
* Test decodes and compares decoded output of two files.
*/
@@ -185,7 +503,7 @@
assertTrue(log + "decoder outputs are not identical", ref.equals(mOutputBuff));
}
}
- verify();
+ CodecDecoderTest.verify(mOutputBuff, mRefFile, mRmsError, mRefCRC);
}
}
}
diff --git a/tests/media/src/android/mediav2/cts/CodecEncoderSurfaceTest.java b/tests/media/src/android/mediav2/cts/CodecEncoderSurfaceTest.java
index 8a578f7..59aee43 100644
--- a/tests/media/src/android/mediav2/cts/CodecEncoderSurfaceTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecEncoderSurfaceTest.java
@@ -83,9 +83,7 @@
static {
android.os.Bundle args = InstrumentationRegistry.getArguments();
- CodecTestBase.codecSelKeys = args.getString(CodecTestBase.CODEC_SEL_KEY);
- if (CodecTestBase.codecSelKeys == null)
- CodecTestBase.codecSelKeys = CodecTestBase.CODEC_SEL_VALUE;
+ CodecTestBase.mimeSelKeys = args.getString(CodecTestBase.MIME_SEL_KEY);
}
public CodecEncoderSurfaceTest(String mime, String testFile, int bitrate, int frameRate) {
@@ -567,4 +565,3 @@
}
}
}
-
diff --git a/tests/media/src/android/mediav2/cts/CodecEncoderTest.java b/tests/media/src/android/mediav2/cts/CodecEncoderTest.java
index 0d5f49c..3d16bd7 100644
--- a/tests/media/src/android/mediav2/cts/CodecEncoderTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecEncoderTest.java
@@ -759,7 +759,6 @@
/**
* Test set parameters : force key frame
*/
- @Ignore("TODO(b/151302863)")
@LargeTest
@Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
public void testSetForceSyncFrame() throws IOException, InterruptedException {
@@ -856,7 +855,6 @@
/**
* Test set parameters : change bitrate dynamically
*/
- @Ignore("TODO(b/151302863)")
@LargeTest
@Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
public void testAdaptiveBitRate() throws IOException, InterruptedException {
diff --git a/tests/media/src/android/mediav2/cts/CodecTestActivity.java b/tests/media/src/android/mediav2/cts/CodecTestActivity.java
index fb20f2c..12bcf38 100644
--- a/tests/media/src/android/mediav2/cts/CodecTestActivity.java
+++ b/tests/media/src/android/mediav2/cts/CodecTestActivity.java
@@ -25,6 +25,7 @@
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;
+import android.view.WindowManager;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
@@ -42,6 +43,11 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ setTurnScreenOn(true);
+ setShowWhenLocked(true);
+
setContentView(R.layout.media_decoder_surface_layout);
mSurfaceView = findViewById(R.id.surface);
mHolder = mSurfaceView.getHolder();
diff --git a/tests/media/src/android/mediav2/cts/CodecTestBase.java b/tests/media/src/android/mediav2/cts/CodecTestBase.java
index 795ff91..93e8c90 100644
--- a/tests/media/src/android/mediav2/cts/CodecTestBase.java
+++ b/tests/media/src/android/mediav2/cts/CodecTestBase.java
@@ -35,6 +35,7 @@
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Assert;
+import org.junit.Assume;
import java.io.File;
import java.io.FileInputStream;
@@ -55,6 +56,8 @@
import java.util.concurrent.locks.ReentrantLock;
import java.util.zip.CRC32;
+import com.android.compatibility.common.util.ApiLevelUtil;
+
import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
import static org.junit.Assert.assertEquals;
@@ -503,9 +506,11 @@
}
abstract class CodecTestBase {
+ public static final boolean IS_AT_LEAST_R = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R);
private static final String LOG_TAG = CodecTestBase.class.getSimpleName();
- static final String CODEC_SEL_KEY = "codec-sel";
- static final String CODEC_SEL_VALUE = "default";
+
+ static final String CODEC_PREFIX_KEY = "codec-prefix";
+ static final String MIME_SEL_KEY = "mime-sel";
static final Map<String, String> codecSelKeyMimeMap = new HashMap<>();
static final boolean ENABLE_LOGS = false;
static final int PER_TEST_TIMEOUT_LARGE_TEST_MS = 300000;
@@ -520,7 +525,8 @@
static final String mInpPrefix = WorkDir.getMediaDirString();
static final PackageManager pm =
InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
- static String codecSelKeys;
+ static String mimeSelKeys;
+ static String codecPrefix;
CodecAsyncHandler mAsyncHandle;
boolean mIsCodecInAsyncMode;
@@ -565,8 +571,8 @@
codecSelKeyMimeMap.put("gsm", MediaFormat.MIMETYPE_AUDIO_MSGSM);
android.os.Bundle args = InstrumentationRegistry.getArguments();
- codecSelKeys = args.getString(CODEC_SEL_KEY);
- if (codecSelKeys == null) codecSelKeys = CODEC_SEL_VALUE;
+ mimeSelKeys = args.getString(MIME_SEL_KEY);
+ codecPrefix = args.getString(CODEC_PREFIX_KEY);
}
static boolean isTv() {
@@ -605,11 +611,11 @@
}
static boolean hasDecoder(String mime) {
- return CodecTestBase.selectCodecs(mime, null, null, false).size() != 0;
+ return CodecTestBase.selectCodecs(mime, null, null, false, false).size() != 0;
}
static boolean hasEncoder(String mime) {
- return CodecTestBase.selectCodecs(mime, null, null, true).size() != 0;
+ return CodecTestBase.selectCodecs(mime, null, null, true, false).size() != 0;
}
static ArrayList<String> prepareRequiredArgsList(boolean isEncoder, boolean needAudio,
@@ -685,7 +691,7 @@
ArrayList<String> cddRequiredMimeList =
prepareRequiredArgsList(isEncoder, needAudio, needVideo);
ArrayList<String> mimes = new ArrayList<>();
- if (codecSelKeys.contains(CODEC_SEL_VALUE)) {
+ if (mimeSelKeys == null) {
MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
for (MediaCodecInfo codecInfo : codecInfos) {
@@ -723,7 +729,7 @@
for (Map.Entry<String, String> entry : codecSelKeyMimeMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
- if (codecSelKeys.contains(key) && !mimes.contains(value)) mimes.add(value);
+ if (mimeSelKeys.contains(key) && !mimes.contains(value)) mimes.add(value);
}
}
final List<Object[]> argsList = new ArrayList<>();
@@ -905,13 +911,22 @@
}
static ArrayList<String> selectCodecs(String mime, ArrayList<MediaFormat> formats,
- String[] features, boolean isEncoder) {
+ String[] features, boolean isEncoder) {
+ return selectCodecs(mime, formats, features, isEncoder, true);
+ }
+
+ static ArrayList<String> selectCodecs(String mime, ArrayList<MediaFormat> formats,
+ String[] features, boolean isEncoder, boolean enableCodecFilter) {
MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
ArrayList<String> listOfCodecs = new ArrayList<>();
for (MediaCodecInfo codecInfo : codecInfos) {
if (codecInfo.isEncoder() != isEncoder) continue;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && codecInfo.isAlias()) continue;
+ if (enableCodecFilter && codecPrefix != null &&
+ !codecInfo.getName().startsWith(codecPrefix)) {
+ continue;
+ }
String[] types = codecInfo.getSupportedTypes();
for (String type : types) {
if (type.equalsIgnoreCase(mime)) {
@@ -938,6 +953,10 @@
}
}
}
+ if (enableCodecFilter && codecPrefix != null) {
+ Assume.assumeFalse("Skipping test because of --codec-prefix " + codecPrefix,
+ listOfCodecs.isEmpty());
+ }
return listOfCodecs;
}
diff --git a/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java b/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java
index 5d780f0..8b77f73 100644
--- a/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java
+++ b/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java
@@ -209,7 +209,8 @@
AVCProfileConstrainedBaseline, AVCProfileConstrainedHigh});
mProfileMap.put(MediaFormat.MIMETYPE_VIDEO_HEVC,
new int[]{HEVCProfileMain, HEVCProfileMain10, HEVCProfileMainStill,
- HEVCProfileMain10HDR10, HEVCProfileMain10HDR10Plus});
+ // TODO: test HDR profiles once they are supported by MediaMuxer
+ /* HEVCProfileMain10HDR10, HEVCProfileMain10HDR10Plus */});
mProfileMap.put(MediaFormat.MIMETYPE_VIDEO_H263,
new int[]{H263ProfileBaseline, H263ProfileH320Coding,
H263ProfileBackwardCompatible, H263ProfileISWV2, H263ProfileISWV3,
@@ -229,8 +230,9 @@
mProfileMap.put(MediaFormat.MIMETYPE_VIDEO_VP8, new int[]{VP8ProfileMain});
mProfileMap.put(MediaFormat.MIMETYPE_VIDEO_VP9, new int[]{VP9Profile0, VP9Profile1});
mProfileMap.put(MediaFormat.MIMETYPE_VIDEO_AV1,
- new int[]{AV1ProfileMain8, AV1ProfileMain10, AV1ProfileMain10HDR10,
- AV1ProfileMain10HDR10Plus});
+ new int[]{AV1ProfileMain8, AV1ProfileMain10,
+ // TODO: test HDR profiles once they are supported by MediaMuxer
+ /* AV1ProfileMain10HDR10, AV1ProfileMain10HDR10Plus */});
mProfileMap.put(MediaFormat.MIMETYPE_AUDIO_AAC,
new int[]{AACObjectMain, AACObjectLC, AACObjectSSR, AACObjectLTP, AACObjectHE,
AACObjectScalable, AACObjectERLC, AACObjectERScalable, AACObjectLD,
@@ -622,6 +624,26 @@
super.dequeueOutput(bufferIndex, info);
}
+ private int getAacProfile(MediaFormat format) {
+ int aacProfile = format.getInteger(MediaFormat.KEY_AAC_PROFILE, -1);
+ int profile = format.getInteger(MediaFormat.KEY_PROFILE, -1);
+
+ if (aacProfile != -1 && profile != -1) {
+ // If both aac-profile and profile are present in format, then they must be the same
+ assertTrue("aac-profile " + aacProfile + " and profile " + profile + " are different.",
+ aacProfile == profile);
+ return aacProfile;
+ } else if (aacProfile != -1) {
+ return aacProfile;
+ } else if (profile != -1) {
+ return profile;
+ } else {
+ Log.e(LOG_TAG,
+ "format doesn't contain either KEY_AAC_PROFILE or KEY_PROFILE");
+ return -1;
+ }
+ }
+
@Override
boolean isFormatSimilar(MediaFormat inpFormat, MediaFormat outFormat) {
if (!super.isFormatSimilar(inpFormat, outFormat)) {
@@ -634,28 +656,11 @@
if (outMime.startsWith("audio/")) {
if (outFormat.getString(MediaFormat.KEY_MIME).equals(MediaFormat.MIMETYPE_AUDIO_AAC)) {
int inputProfileKey, outputProfileKey;
- if (outFormat.containsKey(MediaFormat.KEY_AAC_PROFILE)) {
- outputProfileKey = outFormat.getInteger(MediaFormat.KEY_AAC_PROFILE);
- } else if (outFormat.containsKey(MediaFormat.KEY_PROFILE)) {
- outputProfileKey = outFormat.getInteger(MediaFormat.KEY_PROFILE);
- } else {
- Log.e(LOG_TAG,
- "Output format doesn't contain either KEY_AAC_PROFILE or KEY_PROFILE");
- return false;
- }
- if (inpFormat.containsKey(MediaFormat.KEY_AAC_PROFILE)) {
- inputProfileKey = inpFormat.getInteger(MediaFormat.KEY_AAC_PROFILE);
- } else if (inpFormat.containsKey(MediaFormat.KEY_PROFILE)) {
- inputProfileKey = inpFormat.getInteger(MediaFormat.KEY_PROFILE);
- } else {
- Log.e(LOG_TAG,
- "Input format doesn't contain either KEY_AAC_PROFILE or KEY_PROFILE");
- return false;
- }
+ outputProfileKey = getAacProfile(outFormat);
+ inputProfileKey = getAacProfile(inpFormat);
if (outputProfileKey != inputProfileKey) {
- Log.e(LOG_TAG, "aac-profile in output doesn't match configured input");
- //TODO (b/151429829)
- if (true) return true;
+ Log.e(LOG_TAG, "aac-profile in output " + outputProfileKey +
+ " doesn't match configured input " + inputProfileKey);
return false;
}
}
@@ -730,8 +735,12 @@
MediaCodecInfo.CodecCapabilities codecCapabilities =
mCodec.getCodecInfo().getCapabilitiesForType(mMime);
for (int profile : profiles) {
- format.setInteger(mIsAudio ? MediaFormat.KEY_AAC_PROFILE : MediaFormat.KEY_PROFILE,
- profile);
+ format.setInteger(MediaFormat.KEY_PROFILE, profile);
+ // for aac encoder, alongwith setting profile, also set aac-profile as some
+ // encoders may only support one of the two keys
+ if (mMime.equals(MediaFormat.MIMETYPE_AUDIO_AAC)) {
+ format.setInteger(MediaFormat.KEY_AAC_PROFILE, profile);
+ }
int level = mIsAudio ? 0 : getMinLevel(mMime, mWidth, mHeight,
format.getInteger(MediaFormat.KEY_FRAME_RATE),
format.getInteger(MediaFormat.KEY_BIT_RATE), profile);
@@ -752,6 +761,8 @@
continue;
}
for (boolean isAsync : boolStates) {
+ mOutputBuff.reset();
+ mInfoList.clear();
configureCodec(format, isAsync, true, true);
mCodec.start();
doWork(1);
@@ -769,7 +780,7 @@
(ENABLE_LOGS ? "\n output format:" + outFormat : ""),
isFormatSimilar(format, outFormat));
- // TODO (b/151429829) (b/151398466)
+ // TODO (b/151398466)
if (mMime.equals(MediaFormat.MIMETYPE_AUDIO_AAC)) {
Assume.assumeTrue("neither KEY_AAC_PROFILE nor KEY_PROFILE are present",
outFormat.containsKey(MediaFormat.KEY_AAC_PROFILE) ||
@@ -795,6 +806,15 @@
Log.w(LOG_TAG, "Skip validation after muxing for mime = " + mMime);
continue;
}
+ // TODO (b/184889671) aac for profile AACObjectHE fails validation
+ // TODO (b/184890155) aac for profile AACObjectLD, AACObjectELD fails validation
+ if (mMime.equals(MediaFormat.MIMETYPE_AUDIO_AAC) &&
+ profile != AACObjectLC) {
+ Log.w(LOG_TAG, "Skip validation after muxing for mime = " + mMime +
+ " profile " + profile);
+ continue;
+ }
+
for (int muxerFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_FIRST;
muxerFormat <= MediaMuxer.OutputFormat.MUXER_OUTPUT_LAST; muxerFormat++) {
if (!MuxerTest.isCodecContainerPairValid(mMime, muxerFormat)) continue;
diff --git a/tests/media/src/android/mediav2/cts/ExtractorTest.java b/tests/media/src/android/mediav2/cts/ExtractorTest.java
index e2a9b57..ad0a448 100644
--- a/tests/media/src/android/mediav2/cts/ExtractorTest.java
+++ b/tests/media/src/android/mediav2/cts/ExtractorTest.java
@@ -765,7 +765,6 @@
@Parameterized.Parameters(name = "{index}({0})")
public static Collection<Object[]> input() {
- /* TODO(b/157108639) - add missing test files */
return Arrays.asList(new Object[][]{
{MediaFormat.MIMETYPE_VIDEO_MPEG2, new String[]{
"bbb_cif_768kbps_30fps_mpeg2_stereo_48kHz_192kbps_mp3.mp4",
diff --git a/tests/media/src/android/mediav2/cts/MuxerTest.java b/tests/media/src/android/mediav2/cts/MuxerTest.java
index dd5f795..adf6ebc 100644
--- a/tests/media/src/android/mediav2/cts/MuxerTest.java
+++ b/tests/media/src/android/mediav2/cts/MuxerTest.java
@@ -420,6 +420,7 @@
* setOrientationHint are dependent on the mime type and OutputFormat. Legality of these APIs
* are tested in this class.
*/
+ @NonMediaMainlineTest
@SmallTest
@RunWith(Parameterized.class)
public static class TestApi {
@@ -702,6 +703,7 @@
/**
* Tests muxing multiple Video/Audio Tracks
*/
+ @NonMediaMainlineTest
@LargeTest
@RunWith(Parameterized.class)
public static class TestMultiTrack {
@@ -840,6 +842,7 @@
* Add an offset to the presentation time of samples of a track. Mux with the added offset,
* validate by re-extracting the muxer output file and compare with original.
*/
+ @NonMediaMainlineTest
@LargeTest
@RunWith(Parameterized.class)
public static class TestOffsetPts {
@@ -954,6 +957,7 @@
* This test takes the output of a codec and muxes it in to all possible container formats.
* The results are checked for inconsistencies with the requirements of CDD.
*/
+ @NonMediaMainlineTest
@LargeTest
@RunWith(Parameterized.class)
public static class TestSimpleMux {
@@ -1102,6 +1106,7 @@
}
}
+ @NonMediaMainlineTest
@LargeTest
@RunWith(Parameterized.class)
public static class TestAddEmptyTracks {
diff --git a/tests/media/src/android/mediav2/cts/MuxerUnitTest.java b/tests/media/src/android/mediav2/cts/MuxerUnitTest.java
index b648ca2..f23535d 100644
--- a/tests/media/src/android/mediav2/cts/MuxerUnitTest.java
+++ b/tests/media/src/android/mediav2/cts/MuxerUnitTest.java
@@ -53,6 +53,7 @@
// duplicate definitions of hide fields of MediaMuxer.OutputFormat.
private static final int MUXER_OUTPUT_LAST = MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG;
+ @NonMediaMainlineTest
@SmallTest
public static class TestApi {
@Rule
@@ -739,6 +740,7 @@
}
}
+ @NonMediaMainlineTest
@SmallTest
public static class TestApiNative {
@Rule
diff --git a/tests/media/src/android/mediav2/cts/NonMediaMainlineTest.java b/tests/media/src/android/mediav2/cts/NonMediaMainlineTest.java
new file mode 100644
index 0000000..83bc166
--- /dev/null
+++ b/tests/media/src/android/mediav2/cts/NonMediaMainlineTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.mediav2.cts;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for tests that are not related to media mainline.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface NonMediaMainlineTest {
+}
diff --git a/tests/media/src/android/mediav2/cts/WorkDir.java b/tests/media/src/android/mediav2/cts/WorkDir.java
index 27f0429..5d23fdf 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-1.10/");
+ return (getTopDirString() + "test/CtsMediaV2TestCases-1.12/");
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/mediapc/Android.bp b/tests/mediapc/Android.bp
new file mode 100644
index 0000000..dcfdb23
--- /dev/null
+++ b/tests/mediapc/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsMediaPerformanceClassTestCases",
+ defaults: ["cts_defaults"],
+ compile_multilib: "both",
+ static_libs: [
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ "ctstestserver",
+ ],
+ libs: [
+ "org.apache.http.legacy",
+ "android.test.runner",
+ "android.test.base",
+ ],
+ platform_apis: true,
+ srcs: ["src/**/*.java"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+ min_sdk_version: "30",
+}
diff --git a/tests/mediapc/AndroidManifest.xml b/tests/mediapc/AndroidManifest.xml
new file mode 100644
index 0000000..20d030e
--- /dev/null
+++ b/tests/mediapc/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.mediapc.cts">
+
+ <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.CAMERA" />
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+
+ <application
+ android:requestLegacyExternalStorage="true"
+ android:usesCleartextTraffic="true">
+ <uses-library android:name="android.test.runner" />
+ <uses-library android:name="org.apache.http.legacy" />
+ <activity android:name="android.mediapc.cts.TestActivity" />
+ </application>
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.mediapc.cts"
+ android:label="CTS MediaPerformanceClass tests of android.media" >
+ <meta-data
+ android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+</manifest>
diff --git a/tests/mediapc/AndroidTest.xml b/tests/mediapc/AndroidTest.xml
new file mode 100644
index 0000000..1303ba9
--- /dev/null
+++ b/tests/mediapc/AndroidTest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Media Performance Class test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="media" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+ <option name="target" value="host" />
+ <option name="config-filename" value="CtsMediaPerformanceClassTestCases" />
+ <option name="version" value="1.0"/>
+ </target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
+ <option name="push-all" value="true" />
+ <option name="media-folder-name" value="CtsMediaPerformanceClassTestCases-1.0" />
+ <option name="dynamic-config-module" value="CtsMediaPerformanceClassTestCases" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsMediaPerformanceClassTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.mediapc.cts" />
+ </test>
+</configuration>
diff --git a/tests/mediapc/DynamicConfig.xml b/tests/mediapc/DynamicConfig.xml
new file mode 100644
index 0000000..73348b4
--- /dev/null
+++ b/tests/mediapc/DynamicConfig.xml
@@ -0,0 +1,6 @@
+<dynamicConfig>
+ <entry key="media_files_url">
+ <value>https://storage.googleapis.com/android_media/cts/tests/mediapc/CtsMediaPerformanceClassTestCases-1.0.zip</value>
+ </entry>
+</dynamicConfig>
+
diff --git a/tests/mediapc/OWNERS b/tests/mediapc/OWNERS
new file mode 100644
index 0000000..091c4df
--- /dev/null
+++ b/tests/mediapc/OWNERS
@@ -0,0 +1,14 @@
+# Bug component: 1344
+# include media developers and framework video team
+include platform/frameworks/av:/media/OWNERS
+chz@google.com
+dichenzhang@google.com
+essick@google.com
+gokrishnan@google.com
+lajos@google.com
+taklee@google.com
+wonsik@google.com
+
+# LON
+olly@google.com
+andrewlewis@google.com
diff --git a/tests/mediapc/README.md b/tests/mediapc/README.md
new file mode 100644
index 0000000..d1d8a21
--- /dev/null
+++ b/tests/mediapc/README.md
@@ -0,0 +1,10 @@
+## Media Performance Class CTS Tests
+Current folder comprises of files necessary for testing media performance class.
+
+The test vectors used by the test suite is available at [link](https://storage.googleapis.com/android_media/cts/tests/mediapc/CtsMediaPerformanceClassTestCases-1.0.zip) and is downloaded automatically while running tests. Manual installation of these can be done using copy_media.sh script in this directory.
+
+### Commands
+```sh
+$ atest android.mediapc.cts
+$ atest android.mediapc.cts.PeformanceClassTest
+```
diff --git a/tests/mediapc/copy_media.sh b/tests/mediapc/copy_media.sh
new file mode 100644
index 0000000..95919a5
--- /dev/null
+++ b/tests/mediapc/copy_media.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# 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.
+#
+
+## script to install media performance class test files manually
+
+adbOptions=" "
+resLabel=CtsMediaPerformanceClassTestCases-1.0
+srcDir="/tmp/$resLabel"
+tgtDir="/sdcard/test"
+usage="Usage: $0 [-h] [-s serial]"
+
+if [ $# -gt 0 ]; then
+ if [ "$1" = "-h" ]; then
+ echo $usage
+ exit 1
+ elif [ "$1" = "-s" -a "$2" != "" ] ; then
+ adbOptions=""$1" "$2""
+ else
+ echo "bad options"
+ echo $usage
+ exit 1
+ fi
+fi
+
+## download resources if not already done
+if [ ! -f "/tmp/$resLabel.zip" ]; then
+ wget "https://storage.googleapis.com/android_media/cts/tests/mediapc/$resLabel.zip" -O /tmp/$resLabel.zip
+fi
+unzip -qo "/tmp/$resLabel" -d $srcDir
+
+## install on target device
+echo "adb $adbOptions push $srcDir $tgtDir"
+adb $adbOptions shell mkdir -p $tgtDir
+adb $adbOptions push $srcDir/. $tgtDir
diff --git a/tests/mediapc/res/layout/media_decoder_surface_layout.xml b/tests/mediapc/res/layout/media_decoder_surface_layout.xml
new file mode 100644
index 0000000..bff09bb
--- /dev/null
+++ b/tests/mediapc/res/layout/media_decoder_surface_layout.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <SurfaceView android:id="@+id/surface"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ </SurfaceView>
+</LinearLayout>
diff --git a/tests/mediapc/src/android/mediapc/cts/AdaptivePlaybackFrameDropTest.java b/tests/mediapc/src/android/mediapc/cts/AdaptivePlaybackFrameDropTest.java
new file mode 100644
index 0000000..495eae1
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/AdaptivePlaybackFrameDropTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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 android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaFormat;
+import android.view.Surface;
+
+import androidx.test.filters.LargeTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import static org.junit.Assert.assertTrue;
+
+@RunWith(Parameterized.class)
+public class AdaptivePlaybackFrameDropTest extends FrameDropTestBase {
+ private static final String LOG_TAG = AdaptivePlaybackFrameDropTest.class.getSimpleName();
+
+ public AdaptivePlaybackFrameDropTest(String mimeType, String decoderName, boolean isAsync) {
+ super(mimeType, decoderName, isAsync);
+ }
+
+ @Parameterized.Parameters(name = "{index}({0}_{1}_{2})")
+ public static Collection<Object[]> inputParams() {
+ return prepareArgumentsList(new String[]{
+ MediaCodecInfo.CodecCapabilities.FEATURE_AdaptivePlayback});
+ }
+
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ public void testAdaptivePlaybackFrameDrop() throws Exception {
+ for (int i = 0; i < 5; i++) {
+ AdaptivePlayback adaptivePlayback = new AdaptivePlayback(mMime,
+ new String[]{m1080pTestFiles.get(mMime), m540pTestFiles.get(mMime),
+ m1080pTestFiles.get(mMime)},
+ mDecoderName, mSurface, mIsAsync);
+ adaptivePlayback.doAdaptivePlaybackAndCalculateFrameDrop();
+ }
+ }
+}
+
+class AdaptivePlayback extends DecodeExtractedSamplesTestBase {
+ private final String mDecoderName;
+
+ AdaptivePlayback(String mime, String[] testFiles, String decoderName, Surface surface,
+ boolean isAsync) {
+ super(mime, testFiles, surface, isAsync);
+ mDecoderName = decoderName;
+ }
+
+ public void doAdaptivePlaybackAndCalculateFrameDrop() throws Exception {
+ ArrayList<MediaFormat> formats = setUpSourceFiles();
+ mCodec = MediaCodec.createByCodecName(mDecoderName);
+ configureCodec(formats.get(0), mIsAsync, false, false);
+ mCodec.start();
+ doWork(mBuff, mBufferInfos);
+ queueEOS();
+ waitForAllOutputs();
+ mCodec.stop();
+ mCodec.release();
+ assertTrue("FrameDrop count for mime: " + mMime + " decoder: " + mDecoderName +
+ " is not as expected. act/exp: " + mFrameDropCount + "/0", mFrameDropCount == 0);
+ }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/AudioPlaybackLoad.java b/tests/mediapc/src/android/mediapc/cts/AudioPlaybackLoad.java
new file mode 100644
index 0000000..bc9cc22
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/AudioPlaybackLoad.java
@@ -0,0 +1,137 @@
+/*
+ * 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 android.media.AudioAttributes;
+import android.media.AudioFormat;
+import android.media.AudioTrack;
+import android.media.MediaCodec;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+
+import java.nio.ByteBuffer;
+
+class AudioPlaybackLoad extends CodecDecoderTestBase {
+ private final String mDecoderName;
+ private final LoadStatus mLoadStatus;
+
+ private long mBasePts;
+ private long mMaxPts;
+ private AudioTrack mTrack;
+
+ AudioPlaybackLoad(String mime, String testFile, String decoderName, LoadStatus loadStatus) {
+ super(mime, testFile);
+ mDecoderName = decoderName;
+ mLoadStatus = loadStatus;
+ mBasePts = 0;
+ mMaxPts = 0;
+ }
+
+ public void doDecodeAndPlayback() throws Exception {
+ MediaFormat format = setUpSource(mTestFile);
+ mTrack = createAudioTrack(format);
+ mTrack.play();
+ mCodec = MediaCodec.createByCodecName(mDecoderName);
+ mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+ configureCodec(format, false, false, false);
+ mCodec.start();
+ doWork(Integer.MAX_VALUE);
+ queueEOS();
+ waitForAllOutputs();
+ mCodec.stop();
+ mCodec.release();
+ mExtractor.release();
+ mTrack.pause();
+ mTrack.flush();
+ mTrack.release();
+ }
+
+ private AudioTrack createAudioTrack(MediaFormat format) {
+ final int channelMask = getChannelMask(format);
+ final int encoding = AudioFormat.ENCODING_PCM_16BIT;
+ final int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
+ final AudioFormat audioFormat = new AudioFormat.Builder()
+ .setEncoding(encoding)
+ .setSampleRate(sampleRate)
+ .setChannelMask(channelMask)
+ .build();
+ final AudioAttributes audioAttributes = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_MEDIA)
+ .setContentType(AudioAttributes.CONTENT_TYPE_MOVIE)
+ .build();
+ final int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelMask, encoding);
+ final int bufferSize = 2 * minBufferSize;
+ return new AudioTrack.Builder()
+ .setBufferSizeInBytes(bufferSize)
+ .setAudioAttributes(audioAttributes)
+ .setAudioFormat(audioFormat)
+ .build();
+ }
+
+ private int getChannelMask(MediaFormat format) {
+ final int count = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
+ if (count == 1) {
+ return AudioFormat.CHANNEL_OUT_MONO;
+ } else if (count == 2) {
+ return AudioFormat.CHANNEL_OUT_STEREO;
+ } else if (count == 6) {
+ return AudioFormat.CHANNEL_OUT_5POINT1;
+ }
+ return -1;
+ }
+
+ @Override
+ void enqueueInput(int bufferIndex) {
+ if (mExtractor.getSampleSize() < 0) {
+ enqueueEOS(bufferIndex);
+ } else {
+ ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
+ int size = mExtractor.readSampleData(inputBuffer, 0);
+ long pts = mExtractor.getSampleTime();
+ mMaxPts = Math.max(mMaxPts, mBasePts + pts);
+ int extractorFlags = mExtractor.getSampleFlags();
+ int codecFlags = 0;
+ if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
+ codecFlags |= MediaCodec.BUFFER_FLAG_KEY_FRAME;
+ }
+ mCodec.queueInputBuffer(bufferIndex, 0, size, mBasePts + pts, codecFlags);
+ if (size > 0 && (codecFlags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+ mInputCount++;
+ }
+ if (!mExtractor.advance() && !mLoadStatus.isLoadFinished()) {
+ mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+ mBasePts = mMaxPts + 1000000L;
+ }
+ }
+ }
+
+ @Override
+ void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ mSawOutputEOS = true;
+ }
+ if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+ mOutputCount++;
+ }
+ final ByteBuffer buffer = mCodec.getOutputBuffer(bufferIndex);
+ final byte[] audio = new byte[info.size];
+ buffer.clear(); // prepare buffer for reading
+ buffer.get(audio);
+ mTrack.write(audio, 0, audio.length);
+ mCodec.releaseOutputBuffer(bufferIndex, false);
+ }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/CodecTestBase.java b/tests/mediapc/src/android/mediapc/cts/CodecTestBase.java
new file mode 100644
index 0000000..5aad0bd
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/CodecTestBase.java
@@ -0,0 +1,825 @@
+/*
+ * 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 android.graphics.ImageFormat;
+import android.media.Image;
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecList;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.os.Build;
+import android.util.Log;
+import android.util.Pair;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+
+import org.junit.Assert;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.concurrent.Callable;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+class CodecAsyncHandler extends MediaCodec.Callback {
+ private static final String LOG_TAG = CodecAsyncHandler.class.getSimpleName();
+ private final Lock mLock = new ReentrantLock();
+ private final Condition mCondition = mLock.newCondition();
+ private final LinkedList<Pair<Integer, MediaCodec.BufferInfo>> mCbInputQueue;
+ private final LinkedList<Pair<Integer, MediaCodec.BufferInfo>> mCbOutputQueue;
+ private MediaFormat mOutFormat;
+ private boolean mSignalledOutFormatChanged;
+ private volatile boolean mSignalledError;
+
+ CodecAsyncHandler() {
+ mCbInputQueue = new LinkedList<>();
+ mCbOutputQueue = new LinkedList<>();
+ mSignalledError = false;
+ mSignalledOutFormatChanged = false;
+ }
+
+ void clearQueues() {
+ mLock.lock();
+ mCbInputQueue.clear();
+ mCbOutputQueue.clear();
+ mLock.unlock();
+ }
+
+ void resetContext() {
+ clearQueues();
+ mOutFormat = null;
+ mSignalledOutFormatChanged = false;
+ mSignalledError = false;
+ }
+
+ @Override
+ public void onInputBufferAvailable(@NonNull MediaCodec codec, int bufferIndex) {
+ assertTrue(bufferIndex >= 0);
+ mLock.lock();
+ mCbInputQueue.add(new Pair<>(bufferIndex, (MediaCodec.BufferInfo) null));
+ mCondition.signalAll();
+ mLock.unlock();
+ }
+
+ @Override
+ public void onOutputBufferAvailable(@NonNull MediaCodec codec, int bufferIndex,
+ @NonNull MediaCodec.BufferInfo info) {
+ assertTrue(bufferIndex >= 0);
+ mLock.lock();
+ mCbOutputQueue.add(new Pair<>(bufferIndex, info));
+ mCondition.signalAll();
+ mLock.unlock();
+ }
+
+ @Override
+ public void onError(@NonNull MediaCodec codec, MediaCodec.CodecException e) {
+ mLock.lock();
+ mSignalledError = true;
+ mCondition.signalAll();
+ mLock.unlock();
+ Log.e(LOG_TAG, "received media codec error : " + e.getMessage());
+ }
+
+ @Override
+ public void onOutputFormatChanged(@NonNull MediaCodec codec, @NonNull MediaFormat format) {
+ mOutFormat = format;
+ mSignalledOutFormatChanged = true;
+ Log.i(LOG_TAG, "Output format changed: " + format.toString());
+ }
+
+ void setCallBack(MediaCodec codec, boolean isCodecInAsyncMode) {
+ if (isCodecInAsyncMode) {
+ codec.setCallback(this);
+ } else {
+ codec.setCallback(null);
+ }
+ }
+
+ Pair<Integer, MediaCodec.BufferInfo> getOutput() throws InterruptedException {
+ Pair<Integer, MediaCodec.BufferInfo> element = null;
+ mLock.lock();
+ while (!mSignalledError) {
+ if (mCbOutputQueue.isEmpty()) {
+ mCondition.await();
+ } else {
+ element = mCbOutputQueue.remove(0);
+ break;
+ }
+ }
+ mLock.unlock();
+ return element;
+ }
+
+ Pair<Integer, MediaCodec.BufferInfo> getWork() throws InterruptedException {
+ Pair<Integer, MediaCodec.BufferInfo> element = null;
+ mLock.lock();
+ while (!mSignalledError) {
+ if (mCbInputQueue.isEmpty() && mCbOutputQueue.isEmpty()) {
+ mCondition.await();
+ } else {
+ if (!mCbOutputQueue.isEmpty()) {
+ element = mCbOutputQueue.remove(0);
+ break;
+ }
+ if (!mCbInputQueue.isEmpty()) {
+ element = mCbInputQueue.remove(0);
+ break;
+ }
+ }
+ }
+ mLock.unlock();
+ return element;
+ }
+
+ boolean hasSeenError() {
+ return mSignalledError;
+ }
+
+ boolean hasOutputFormatChanged() {
+ return mSignalledOutFormatChanged;
+ }
+
+ MediaFormat getOutputFormat() {
+ return mOutFormat;
+ }
+}
+
+abstract class CodecTestBase {
+ private static final String LOG_TAG = CodecTestBase.class.getSimpleName();
+ static final boolean ENABLE_LOGS = false;
+ static final int PER_TEST_TIMEOUT_LARGE_TEST_MS = 300000;
+ 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
+ // 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
+ static final String mInpPrefix = WorkDir.getMediaDirString();
+
+ CodecAsyncHandler mAsyncHandle;
+ boolean mIsCodecInAsyncMode;
+ boolean mSawInputEOS;
+ boolean mSawOutputEOS;
+ boolean mSignalEOSWithLastFrame;
+ int mInputCount;
+ int mOutputCount;
+ long mPrevOutputPts;
+ boolean mSignalledOutFormatChanged;
+ MediaFormat mOutFormat;
+ boolean mIsAudio;
+
+ MediaCodec mCodec;
+ Surface mSurface;
+
+ abstract void enqueueInput(int bufferIndex) throws IOException;
+
+ abstract void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info);
+
+ void configureCodec(MediaFormat format, boolean isAsync, boolean signalEOSWithLastFrame,
+ boolean isEncoder) {
+ resetContext(isAsync, signalEOSWithLastFrame);
+ mAsyncHandle.setCallBack(mCodec, isAsync);
+ // signalEOS flag has nothing to do with configure. We are using this flag to try all
+ // available configure apis
+ if (signalEOSWithLastFrame) {
+ mCodec.configure(format, mSurface, null,
+ isEncoder ? MediaCodec.CONFIGURE_FLAG_ENCODE : 0);
+ } else {
+ mCodec.configure(format, mSurface, isEncoder ? MediaCodec.CONFIGURE_FLAG_ENCODE : 0,
+ null);
+ }
+ }
+
+ void resetContext(boolean isAsync, boolean signalEOSWithLastFrame) {
+ mAsyncHandle.resetContext();
+ mIsCodecInAsyncMode = isAsync;
+ mSawInputEOS = false;
+ mSawOutputEOS = false;
+ mSignalEOSWithLastFrame = signalEOSWithLastFrame;
+ mInputCount = 0;
+ mOutputCount = 0;
+ mPrevOutputPts = Long.MIN_VALUE;
+ mSignalledOutFormatChanged = false;
+ }
+
+ void enqueueEOS(int bufferIndex) {
+ if (!mSawInputEOS) {
+ mCodec.queueInputBuffer(bufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+ mSawInputEOS = true;
+ if (ENABLE_LOGS) {
+ Log.v(LOG_TAG, "Queued End of Stream");
+ }
+ }
+ }
+
+ void doWork(int frameLimit) throws InterruptedException, IOException {
+ int frameCount = 0;
+ if (mIsCodecInAsyncMode) {
+ // dequeue output after inputEOS is expected to be done in waitForAllOutputs()
+ while (!mAsyncHandle.hasSeenError() && !mSawInputEOS && frameCount < frameLimit) {
+ Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getWork();
+ if (element != null) {
+ int bufferID = element.first;
+ MediaCodec.BufferInfo info = element.second;
+ if (info != null) {
+ // <id, info> corresponds to output callback. Handle it accordingly
+ dequeueOutput(bufferID, info);
+ } else {
+ // <id, null> corresponds to input callback. Handle it accordingly
+ enqueueInput(bufferID);
+ frameCount++;
+ }
+ }
+ }
+ } else {
+ MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
+ // dequeue output after inputEOS is expected to be done in waitForAllOutputs()
+ while (!mSawInputEOS && frameCount < frameLimit) {
+ int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
+ if (outputBufferId >= 0) {
+ dequeueOutput(outputBufferId, outInfo);
+ } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ mOutFormat = mCodec.getOutputFormat();
+ mSignalledOutFormatChanged = true;
+ }
+ int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
+ if (inputBufferId != -1) {
+ enqueueInput(inputBufferId);
+ frameCount++;
+ }
+ }
+ }
+ }
+
+ void queueEOS() throws InterruptedException {
+ if (mIsCodecInAsyncMode) {
+ 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) {
+ dequeueOutput(bufferID, info);
+ } else {
+ enqueueEOS(element.first);
+ }
+ }
+ }
+ } else {
+ MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
+ while (!mSawInputEOS) {
+ int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
+ if (outputBufferId >= 0) {
+ dequeueOutput(outputBufferId, outInfo);
+ } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ mOutFormat = mCodec.getOutputFormat();
+ mSignalledOutFormatChanged = true;
+ }
+ int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
+ if (inputBufferId != -1) {
+ enqueueEOS(inputBufferId);
+ }
+ }
+ }
+ }
+
+ void waitForAllOutputs() throws InterruptedException {
+ if (mIsCodecInAsyncMode) {
+ while (!mAsyncHandle.hasSeenError() && !mSawOutputEOS) {
+ Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getOutput();
+ if (element != null) {
+ dequeueOutput(element.first, element.second);
+ }
+ }
+ } else {
+ MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
+ while (!mSawOutputEOS) {
+ int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
+ if (outputBufferId >= 0) {
+ dequeueOutput(outputBufferId, outInfo);
+ } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ mOutFormat = mCodec.getOutputFormat();
+ mSignalledOutFormatChanged = true;
+ }
+ }
+ }
+ }
+
+ static ArrayList<String> selectCodecs(String mime, ArrayList<MediaFormat> formats,
+ String[] features, boolean isEncoder) {
+ return selectCodecs(mime, formats, features, isEncoder, SELECT_ALL);
+ }
+
+ static ArrayList<String> selectHardwareCodecs(String mime, ArrayList<MediaFormat> formats,
+ String[] features, boolean isEncoder) {
+ return selectCodecs(mime, formats, features, isEncoder, SELECT_HARDWARE);
+ }
+
+ static ArrayList<String> selectCodecs(String mime, ArrayList<MediaFormat> formats,
+ String[] features, boolean isEncoder, int selectCodecOption) {
+ MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
+ ArrayList<String> listOfCodecs = new ArrayList<>();
+ for (MediaCodecInfo codecInfo : codecInfos) {
+ if (codecInfo.isEncoder() != isEncoder) continue;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && codecInfo.isAlias()) continue;
+ if (selectCodecOption == SELECT_HARDWARE && !codecInfo.isHardwareAccelerated())
+ continue;
+ else if (selectCodecOption == SELECT_SOFTWARE && !codecInfo.isSoftwareOnly())
+ continue;
+ String[] types = codecInfo.getSupportedTypes();
+ for (String type : types) {
+ if (type.equalsIgnoreCase(mime)) {
+ boolean isOk = true;
+ MediaCodecInfo.CodecCapabilities codecCapabilities =
+ codecInfo.getCapabilitiesForType(type);
+ if (formats != null) {
+ for (MediaFormat format : formats) {
+ if (!codecCapabilities.isFormatSupported(format)) {
+ isOk = false;
+ break;
+ }
+ }
+ }
+ if (features != null) {
+ for (String feature : features) {
+ if (!codecCapabilities.isFeatureSupported(feature)) {
+ isOk = false;
+ break;
+ }
+ }
+ }
+ if (isOk) listOfCodecs.add(codecInfo.getName());
+ }
+ }
+ }
+ return listOfCodecs;
+ }
+}
+
+class CodecDecoderTestBase extends CodecTestBase {
+ private static final String LOG_TAG = CodecDecoderTestBase.class.getSimpleName();
+
+ String mMime;
+ String mTestFile;
+ boolean mIsInterlaced;
+
+ ArrayList<ByteBuffer> mCsdBuffers;
+
+ MediaExtractor mExtractor;
+
+ CodecDecoderTestBase(String mime, String testFile) {
+ mMime = mime;
+ mTestFile = testFile;
+ mAsyncHandle = new CodecAsyncHandler();
+ mCsdBuffers = new ArrayList<>();
+ mIsAudio = mMime.startsWith("audio/");
+ }
+
+ MediaFormat setUpSource(String srcFile) throws IOException {
+ return setUpSource(mInpPrefix, srcFile);
+ }
+
+ boolean hasCSD(MediaFormat format) {
+ return format.containsKey("csd-0");
+ }
+
+ MediaFormat setUpSource(String prefix, String srcFile) throws IOException {
+ mExtractor = new MediaExtractor();
+ mExtractor.setDataSource(prefix + srcFile);
+ for (int trackID = 0; trackID < mExtractor.getTrackCount(); trackID++) {
+ MediaFormat format = mExtractor.getTrackFormat(trackID);
+ if (mMime.equalsIgnoreCase(format.getString(MediaFormat.KEY_MIME))) {
+ mExtractor.selectTrack(trackID);
+ if (!mIsAudio) {
+ if (mSurface == null) {
+ // COLOR_FormatYUV420Flexible must be supported by all components
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatYUV420Flexible);
+ } else {
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatSurface);
+ }
+ }
+ // TODO: determine this from the extractor format when it becomes exposed.
+ mIsInterlaced = srcFile.contains("_interlaced_");
+ return format;
+ }
+ }
+ fail("No track with mime: " + mMime + " found in file: " + srcFile);
+ return null;
+ }
+
+ void enqueueInput(int bufferIndex, ByteBuffer buffer, MediaCodec.BufferInfo info) {
+ ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
+ inputBuffer.put(buffer.array(), info.offset, info.size);
+ mCodec.queueInputBuffer(bufferIndex, 0, info.size, info.presentationTimeUs,
+ info.flags);
+ if (info.size > 0 && ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) &&
+ ((info.flags & MediaCodec.BUFFER_FLAG_PARTIAL_FRAME) == 0)) {
+ mInputCount++;
+ }
+ }
+
+ void enqueueInput(int bufferIndex) {
+ if (mExtractor.getSampleSize() < 0) {
+ enqueueEOS(bufferIndex);
+ } else {
+ ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
+ int size = mExtractor.readSampleData(inputBuffer, 0);
+ long pts = mExtractor.getSampleTime();
+ int extractorFlags = mExtractor.getSampleFlags();
+ int codecFlags = 0;
+ if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
+ codecFlags |= MediaCodec.BUFFER_FLAG_KEY_FRAME;
+ }
+ if (!mExtractor.advance() && mSignalEOSWithLastFrame) {
+ codecFlags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+ mSawInputEOS = true;
+ }
+ mCodec.queueInputBuffer(bufferIndex, 0, size, pts, codecFlags);
+ if (size > 0 && (codecFlags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+ mInputCount++;
+ }
+ }
+ }
+
+ void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ mSawOutputEOS = true;
+ }
+ if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+ mOutputCount++;
+ }
+ mCodec.releaseOutputBuffer(bufferIndex, false);
+ }
+
+ void doWork(ByteBuffer buffer, ArrayList<MediaCodec.BufferInfo> list)
+ throws InterruptedException {
+ int frameCount = 0;
+ if (mIsCodecInAsyncMode) {
+ // output processing after queuing EOS is done in waitForAllOutputs()
+ while (!mAsyncHandle.hasSeenError() && !mSawInputEOS && frameCount < list.size()) {
+ Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getWork();
+ if (element != null) {
+ int bufferID = element.first;
+ MediaCodec.BufferInfo info = element.second;
+ if (info != null) {
+ dequeueOutput(bufferID, info);
+ } else {
+ enqueueInput(bufferID, buffer, list.get(frameCount));
+ frameCount++;
+ }
+ }
+ }
+ } else {
+ MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
+ // output processing after queuing EOS is done in waitForAllOutputs()
+ while (!mSawInputEOS && frameCount < list.size()) {
+ int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
+ if (outputBufferId >= 0) {
+ dequeueOutput(outputBufferId, outInfo);
+ } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ mOutFormat = mCodec.getOutputFormat();
+ mSignalledOutFormatChanged = true;
+ }
+ int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
+ if (inputBufferId != -1) {
+ enqueueInput(inputBufferId, buffer, list.get(frameCount));
+ frameCount++;
+ }
+ }
+ }
+ }
+}
+
+class CodecEncoderTestBase extends CodecTestBase {
+ private static final String LOG_TAG = CodecEncoderTestBase.class.getSimpleName();
+
+ // 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";
+ private final int INP_FRM_WIDTH = 352;
+ private final int INP_FRM_HEIGHT = 288;
+
+ final String mMime;
+ final String mInputFile;
+ byte[] mInputData;
+ int mNumBytesSubmitted;
+ long mInputOffsetPts;
+
+ int mWidth, mHeight;
+ int mFrameRate;
+ int mMaxBFrames;
+ int mChannels;
+ int mSampleRate;
+
+ CodecEncoderTestBase(String mime) {
+ mMime = mime;
+ mWidth = INP_FRM_WIDTH;
+ mHeight = INP_FRM_HEIGHT;
+ mChannels = 1;
+ mSampleRate = 8000;
+ mFrameRate = 30;
+ mMaxBFrames = 0;
+ if (mime.equals(MediaFormat.MIMETYPE_VIDEO_MPEG4)) mFrameRate = 12;
+ else if (mime.equals(MediaFormat.MIMETYPE_VIDEO_H263)) mFrameRate = 12;
+ mAsyncHandle = new CodecAsyncHandler();
+ mIsAudio = mMime.startsWith("audio/");
+ mInputFile = mIsAudio ? INPUT_AUDIO_FILE : INPUT_VIDEO_FILE;
+ }
+
+ @Override
+ void resetContext(boolean isAsync, boolean signalEOSWithLastFrame) {
+ super.resetContext(isAsync, signalEOSWithLastFrame);
+ mNumBytesSubmitted = 0;
+ mInputOffsetPts = 0;
+ }
+
+ void setUpSource(String srcFile) throws IOException {
+ String inpPath = mInpPrefix + srcFile;
+ try (FileInputStream fInp = new FileInputStream(inpPath)) {
+ int size = (int) new File(inpPath).length();
+ mInputData = new byte[size];
+ fInp.read(mInputData, 0, size);
+ }
+ }
+
+ void fillImage(Image image) {
+ Assert.assertTrue(image.getFormat() == ImageFormat.YUV_420_888);
+ int imageWidth = image.getWidth();
+ int imageHeight = image.getHeight();
+ Image.Plane[] planes = image.getPlanes();
+ int offset = mNumBytesSubmitted;
+ for (int i = 0; i < planes.length; ++i) {
+ ByteBuffer buf = planes[i].getBuffer();
+ int width = imageWidth;
+ int height = imageHeight;
+ int tileWidth = INP_FRM_WIDTH;
+ int tileHeight = INP_FRM_HEIGHT;
+ int rowStride = planes[i].getRowStride();
+ int pixelStride = planes[i].getPixelStride();
+ if (i != 0) {
+ width = imageWidth / 2;
+ height = imageHeight / 2;
+ tileWidth = INP_FRM_WIDTH / 2;
+ tileHeight = INP_FRM_HEIGHT / 2;
+ }
+ if (pixelStride == 1) {
+ if (width == rowStride && width == tileWidth && height == tileHeight) {
+ buf.put(mInputData, offset, width * height);
+ } else {
+ for (int z = 0; z < height; z += tileHeight) {
+ int rowsToCopy = Math.min(height - z, tileHeight);
+ for (int y = 0; y < rowsToCopy; y++) {
+ for (int x = 0; x < width; x += tileWidth) {
+ int colsToCopy = Math.min(width - x, tileWidth);
+ buf.position((z + y) * rowStride + x);
+ buf.put(mInputData, offset + y * tileWidth, colsToCopy);
+ }
+ }
+ }
+ }
+ } else {
+ // do it pixel-by-pixel
+ for (int z = 0; z < height; z += tileHeight) {
+ int rowsToCopy = Math.min(height - z, tileHeight);
+ for (int y = 0; y < rowsToCopy; y++) {
+ int lineOffset = (z + y) * rowStride;
+ for (int x = 0; x < width; x += tileWidth) {
+ int colsToCopy = Math.min(width - x, tileWidth);
+ for (int w = 0; w < colsToCopy; w++) {
+ buf.position(lineOffset + (x + w) * pixelStride);
+ buf.put(mInputData[offset + y * tileWidth + w]);
+ }
+ }
+ }
+ }
+ }
+ offset += tileWidth * tileHeight;
+ }
+ }
+
+ void fillByteBuffer(ByteBuffer inputBuffer) {
+ int offset = 0, frmOffset = mNumBytesSubmitted;
+ for (int plane = 0; plane < 3; plane++) {
+ int width = mWidth;
+ int height = mHeight;
+ int tileWidth = INP_FRM_WIDTH;
+ int tileHeight = INP_FRM_HEIGHT;
+ if (plane != 0) {
+ width = mWidth / 2;
+ height = mHeight / 2;
+ tileWidth = INP_FRM_WIDTH / 2;
+ tileHeight = INP_FRM_HEIGHT / 2;
+ }
+ for (int k = 0; k < height; k += tileHeight) {
+ int rowsToCopy = Math.min(height - k, tileHeight);
+ for (int j = 0; j < rowsToCopy; j++) {
+ for (int i = 0; i < width; i += tileWidth) {
+ int colsToCopy = Math.min(width - i, tileWidth);
+ inputBuffer.position(offset + (k + j) * width + i);
+ inputBuffer.put(mInputData, frmOffset + j * tileWidth, colsToCopy);
+ }
+ }
+ }
+ offset += width * height;
+ frmOffset += tileWidth * tileHeight;
+ }
+ }
+
+ void enqueueInput(int bufferIndex) {
+ ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
+ if (mNumBytesSubmitted >= mInputData.length) {
+ enqueueEOS(bufferIndex);
+ } else {
+ int size;
+ int flags = 0;
+ long pts = mInputOffsetPts;
+ if (mIsAudio) {
+ pts += mNumBytesSubmitted * 1000000L / (2 * mChannels * mSampleRate);
+ size = Math.min(inputBuffer.capacity(), mInputData.length - mNumBytesSubmitted);
+ inputBuffer.put(mInputData, mNumBytesSubmitted, size);
+ if (mNumBytesSubmitted + size >= mInputData.length && mSignalEOSWithLastFrame) {
+ flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+ mSawInputEOS = true;
+ }
+ mNumBytesSubmitted += size;
+ } else {
+ pts += mInputCount * 1000000L / mFrameRate;
+ size = mWidth * mHeight * 3 / 2;
+ int frmSize = INP_FRM_WIDTH * INP_FRM_HEIGHT * 3 / 2;
+ if (mNumBytesSubmitted + frmSize > mInputData.length) {
+ fail("received partial frame to encode");
+ } else {
+ Image img = mCodec.getInputImage(bufferIndex);
+ if (img != null) {
+ fillImage(img);
+ } else {
+ if (mWidth == INP_FRM_WIDTH && mHeight == INP_FRM_HEIGHT) {
+ inputBuffer.put(mInputData, mNumBytesSubmitted, size);
+ } else {
+ fillByteBuffer(inputBuffer);
+ }
+ }
+ }
+ if (mNumBytesSubmitted + frmSize >= mInputData.length && mSignalEOSWithLastFrame) {
+ flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+ mSawInputEOS = true;
+ }
+ mNumBytesSubmitted += frmSize;
+ }
+ mCodec.queueInputBuffer(bufferIndex, 0, size, pts, flags);
+ mInputCount++;
+ }
+ }
+
+ void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ mSawOutputEOS = true;
+ }
+ if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+ mOutputCount++;
+ }
+ mCodec.releaseOutputBuffer(bufferIndex, false);
+ }
+}
+
+class Decode extends CodecDecoderTestBase implements Callable<Double> {
+ private static final String LOG_TAG = Decode.class.getSimpleName();
+
+ final String mDecoderName;
+ final boolean mIsAsync;
+
+ Decode(String mime, String testFile, String decoderName, boolean isAsync) {
+ super(mime, testFile);
+ mDecoderName = decoderName;
+ mSurface = MediaCodec.createPersistentInputSurface();
+ mIsAsync = isAsync;
+ }
+
+ public Double doDecode() throws Exception {
+ MediaFormat format = setUpSource(mTestFile);
+ mCodec = MediaCodec.createByCodecName(mDecoderName);
+ mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+ configureCodec(format, mIsAsync, false, false);
+ mCodec.start();
+ long start = System.currentTimeMillis();
+ doWork(Integer.MAX_VALUE);
+ queueEOS();
+ waitForAllOutputs();
+ long end = System.currentTimeMillis();
+ mCodec.stop();
+ mCodec.release();
+ mExtractor.release();
+ double fps = mOutputCount / ((end - start) / 1000.0);
+ Log.d(LOG_TAG, "Decode Mime: " + mMime + " Decoder: " + mDecoderName +
+ " Achieved fps: " + fps);
+ return fps;
+ }
+
+ @Override
+ public Double call() throws Exception {
+ return doDecode();
+ }
+}
+
+class DecodeToSurface extends Decode {
+
+ DecodeToSurface(String mime, String testFile, String decoderName, Surface surface,
+ boolean isAsync) {
+ super(mime, testFile, decoderName, isAsync);
+ mSurface = surface;
+ }
+
+ void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ mSawOutputEOS = true;
+ }
+ if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+ mOutputCount++;
+ }
+ mCodec.releaseOutputBuffer(bufferIndex, true);
+ }
+}
+
+class Encode extends CodecEncoderTestBase implements Callable<Double> {
+ private static final String LOG_TAG = Encode.class.getSimpleName();
+
+ private final String mEncoderName;
+ private final boolean mIsAsync;
+
+ Encode(String mime, String encoderName, boolean isAsync) {
+ super(mime);
+ mEncoderName = encoderName;
+ mIsAsync = isAsync;
+ mSurface = MediaCodec.createPersistentInputSurface();
+ mFrameRate = 30;
+ }
+
+ private MediaFormat setUpFormat() {
+ MediaFormat format = new MediaFormat();
+ format.setString(MediaFormat.KEY_MIME, mMime);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, 4000000);
+ format.setInteger(MediaFormat.KEY_WIDTH, 1280);
+ format.setInteger(MediaFormat.KEY_HEIGHT, 720);
+ format.setInteger(MediaFormat.KEY_FRAME_RATE, mFrameRate);
+ format.setInteger(MediaFormat.KEY_MAX_B_FRAMES, 0);
+ format.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 1.0f);
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
+ MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible);
+ return format;
+ }
+
+
+ public Double doEncode() throws Exception {
+ MediaFormat format = setUpFormat();
+ mWidth = format.getInteger(MediaFormat.KEY_WIDTH);
+ mHeight = format.getInteger(MediaFormat.KEY_HEIGHT);
+ setUpSource(mInputFile);
+ mCodec = MediaCodec.createByCodecName(mEncoderName);
+ configureCodec(format, mIsAsync, false, true);
+ mCodec.start();
+ long start = System.currentTimeMillis();
+ doWork(Integer.MAX_VALUE);
+ queueEOS();
+ waitForAllOutputs();
+ long end = System.currentTimeMillis();
+ mCodec.stop();
+ mCodec.release();
+ double fps = mOutputCount / ((end - start) / 1000.0);
+ Log.d(LOG_TAG, "Encode Mime: " + mMime + " Encoder: " + mEncoderName +
+ " Achieved fps: " + fps);
+ return fps;
+ }
+
+ @Override
+ public Double call() throws Exception {
+ return doEncode();
+ }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/CodecTranscoderTestBase.java b/tests/mediapc/src/android/mediapc/cts/CodecTranscoderTestBase.java
new file mode 100644
index 0000000..b0c6da2
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/CodecTranscoderTestBase.java
@@ -0,0 +1,470 @@
+/*
+ * 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 android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.util.Log;
+import android.util.Pair;
+import android.view.Surface;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.concurrent.Callable;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class CodecTranscoderTestBase {
+ private static final String LOG_TAG = CodecTranscoderTestBase.class.getSimpleName();
+ private static final boolean ENABLE_LOGS = false;
+ static final String mInpPrefix = WorkDir.getMediaDirString();
+ String mMime;
+ String mTestFile;
+ int mBitrate;
+ int mFrameRate;
+ MediaExtractor mExtractor;
+ int mMaxBFrames;
+ int mLatency;
+
+ MediaCodec mEncoder;
+ CodecAsyncHandler mAsyncHandleEncoder;
+ MediaCodec mDecoder;
+ CodecAsyncHandler mAsyncHandleDecoder;
+ Surface mSurface;
+
+ boolean mSawDecInputEOS;
+ boolean mSawDecOutputEOS;
+ boolean mSawEncOutputEOS;
+ boolean mIsCodecInAsyncMode;
+ boolean mSignalEOSWithLastFrame;
+ boolean mReviseLatency;
+ int mDecInputCount;
+ int mDecOutputCount;
+ int mEncOutputCount;
+
+ CodecTranscoderTestBase(String mime, String testfile, int bitrate, int frameRate) {
+ mMime = mime;
+ mTestFile = testfile;
+ mBitrate = bitrate;
+ mFrameRate = frameRate;
+ mMaxBFrames = 0;
+ mLatency = mMaxBFrames;
+ mReviseLatency = false;
+ mAsyncHandleDecoder = new CodecAsyncHandler();
+ mAsyncHandleEncoder = new CodecAsyncHandler();
+ }
+
+ boolean hasSeenError() {
+ return mAsyncHandleDecoder.hasSeenError() || mAsyncHandleEncoder.hasSeenError();
+ }
+
+ MediaFormat setUpSource(String srcFile) throws IOException {
+ mExtractor = new MediaExtractor();
+ mExtractor.setDataSource(mInpPrefix + srcFile);
+ for (int trackID = 0; trackID < mExtractor.getTrackCount(); trackID++) {
+ MediaFormat format = mExtractor.getTrackFormat(trackID);
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ if (mime.startsWith("video/")) {
+ mExtractor.selectTrack(trackID);
+ // COLOR_FormatYUV420Flexible by default should be supported by all components
+ // This call shouldn't effect configure() call for any codec
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
+ MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible);
+ return format;
+ }
+ }
+ mExtractor.release();
+ fail("No video track found in file: " + srcFile);
+ return null;
+ }
+
+ void resetContext(boolean isAsync, boolean signalEOSWithLastFrame) {
+ mAsyncHandleDecoder.resetContext();
+ mAsyncHandleEncoder.resetContext();
+ mIsCodecInAsyncMode = isAsync;
+ mSignalEOSWithLastFrame = signalEOSWithLastFrame;
+ mSawDecInputEOS = false;
+ mSawDecOutputEOS = false;
+ mSawEncOutputEOS = false;
+ mDecInputCount = 0;
+ mDecOutputCount = 0;
+ mEncOutputCount = 0;
+ }
+
+ void configureCodec(MediaFormat decFormat, MediaFormat encFormat, boolean isAsync,
+ boolean signalEOSWithLastFrame) {
+ resetContext(isAsync, signalEOSWithLastFrame);
+ mAsyncHandleEncoder.setCallBack(mEncoder, isAsync);
+ mEncoder.configure(encFormat, null, MediaCodec.CONFIGURE_FLAG_ENCODE, null);
+ if (mEncoder.getInputFormat().containsKey(MediaFormat.KEY_LATENCY)) {
+ mReviseLatency = true;
+ mLatency = mEncoder.getInputFormat().getInteger(MediaFormat.KEY_LATENCY);
+ }
+ mSurface = mEncoder.createInputSurface();
+ assertTrue("Surface is not valid", mSurface.isValid());
+ mAsyncHandleDecoder.setCallBack(mDecoder, isAsync);
+ mDecoder.configure(decFormat, mSurface, null, 0);
+ if (ENABLE_LOGS) {
+ Log.v(LOG_TAG, "codec configured");
+ }
+ }
+
+ void enqueueDecoderEOS(int bufferIndex) {
+ if (!mSawDecInputEOS) {
+ mDecoder.queueInputBuffer(bufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+ mSawDecInputEOS = true;
+ if (ENABLE_LOGS) {
+ Log.v(LOG_TAG, "Queued End of Stream");
+ }
+ }
+ }
+
+ void enqueueDecoderInput(int bufferIndex) {
+ if (mExtractor.getSampleSize() < 0) {
+ enqueueDecoderEOS(bufferIndex);
+ } else {
+ ByteBuffer inputBuffer = mDecoder.getInputBuffer(bufferIndex);
+ int size = mExtractor.readSampleData(inputBuffer, 0);
+ long pts = mExtractor.getSampleTime();
+ int extractorFlags = mExtractor.getSampleFlags();
+ int codecFlags = 0;
+ if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
+ codecFlags |= MediaCodec.BUFFER_FLAG_KEY_FRAME;
+ }
+ if (!mExtractor.advance() && mSignalEOSWithLastFrame) {
+ codecFlags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+ mSawDecInputEOS = true;
+ }
+ mDecoder.queueInputBuffer(bufferIndex, 0, size, pts, codecFlags);
+ if (size > 0 && (codecFlags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+ mDecInputCount++;
+ }
+ }
+ }
+
+ void dequeueDecoderOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ mSawDecOutputEOS = true;
+ }
+ if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+ mDecOutputCount++;
+ }
+ mDecoder.releaseOutputBuffer(bufferIndex, mSurface != null);
+ }
+
+ void dequeueEncoderOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ mSawEncOutputEOS = true;
+ }
+ if (info.size > 0) {
+ if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+ mEncOutputCount++;
+ }
+ }
+ mEncoder.releaseOutputBuffer(bufferIndex, false);
+ }
+
+ void tryEncoderOutput(long timeOutUs) throws InterruptedException {
+ if (mIsCodecInAsyncMode) {
+ if (!hasSeenError() && !mSawEncOutputEOS) {
+ int retry = 0;
+ while (mReviseLatency) {
+ if (mAsyncHandleEncoder.hasOutputFormatChanged()) {
+ mReviseLatency = false;
+ int actualLatency = mAsyncHandleEncoder.getOutputFormat()
+ .getInteger(MediaFormat.KEY_LATENCY, mLatency);
+ if (mLatency < actualLatency) {
+ mLatency = actualLatency;
+ return;
+ }
+ } else {
+ if (retry > CodecTestBase.RETRY_LIMIT) throw new InterruptedException(
+ "did not receive output format changed for encoder after " +
+ CodecTestBase.Q_DEQ_TIMEOUT_US * CodecTestBase.RETRY_LIMIT +
+ " us");
+ Thread.sleep(CodecTestBase.Q_DEQ_TIMEOUT_US / 1000);
+ retry ++;
+ }
+ }
+ Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandleEncoder.getOutput();
+ if (element != null) {
+ dequeueEncoderOutput(element.first, element.second);
+ }
+ }
+ } else {
+ MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
+ if (!mSawEncOutputEOS) {
+ int outputBufferId = mEncoder.dequeueOutputBuffer(outInfo, timeOutUs);
+ if (outputBufferId >= 0) {
+ dequeueEncoderOutput(outputBufferId, outInfo);
+ } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ mLatency = mEncoder.getOutputFormat()
+ .getInteger(MediaFormat.KEY_LATENCY, mLatency);
+ }
+ }
+ }
+ }
+
+ void waitForAllEncoderOutputs() throws InterruptedException {
+ if (mIsCodecInAsyncMode) {
+ while (!hasSeenError() && !mSawEncOutputEOS) {
+ tryEncoderOutput(CodecTestBase.Q_DEQ_TIMEOUT_US);
+ }
+ } else {
+ while (!mSawEncOutputEOS) {
+ tryEncoderOutput(CodecTestBase.Q_DEQ_TIMEOUT_US);
+ }
+ }
+ }
+
+ void queueEOS() throws InterruptedException {
+ if (mIsCodecInAsyncMode) {
+ while (!mAsyncHandleDecoder.hasSeenError() && !mSawDecInputEOS) {
+ Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandleDecoder.getWork();
+ if (element != null) {
+ int bufferID = element.first;
+ MediaCodec.BufferInfo info = element.second;
+ if (info != null) {
+ dequeueDecoderOutput(bufferID, info);
+ } else {
+ enqueueDecoderEOS(element.first);
+ }
+ }
+ }
+ } else {
+ MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
+ while (!mSawDecInputEOS) {
+ int outputBufferId =
+ mDecoder.dequeueOutputBuffer(outInfo, CodecTestBase.Q_DEQ_TIMEOUT_US);
+ if (outputBufferId >= 0) {
+ dequeueDecoderOutput(outputBufferId, outInfo);
+ }
+ int inputBufferId = mDecoder.dequeueInputBuffer(CodecTestBase.Q_DEQ_TIMEOUT_US);
+ if (inputBufferId != -1) {
+ enqueueDecoderEOS(inputBufferId);
+ }
+ }
+ }
+ if (mIsCodecInAsyncMode) {
+ while (!hasSeenError() && !mSawDecOutputEOS) {
+ Pair<Integer, MediaCodec.BufferInfo> decOp = mAsyncHandleDecoder.getOutput();
+ if (decOp != null) dequeueDecoderOutput(decOp.first, decOp.second);
+ if (mSawDecOutputEOS) mEncoder.signalEndOfInputStream();
+ if (mDecOutputCount - mEncOutputCount > mLatency) {
+ tryEncoderOutput(-1);
+ }
+ }
+ } else {
+ MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
+ while (!mSawDecOutputEOS) {
+ int outputBufferId =
+ mDecoder.dequeueOutputBuffer(outInfo, CodecTestBase.Q_DEQ_TIMEOUT_US);
+ if (outputBufferId >= 0) {
+ dequeueDecoderOutput(outputBufferId, outInfo);
+ }
+ if (mSawDecOutputEOS) mEncoder.signalEndOfInputStream();
+ if (mDecOutputCount - mEncOutputCount > mLatency) {
+ tryEncoderOutput(-1);
+ }
+ }
+ }
+ }
+
+ void doWork(int frameLimit) throws InterruptedException {
+ int frameCnt = 0;
+ if (mIsCodecInAsyncMode) {
+ // dequeue output after inputEOS is expected to be done in waitForAllOutputs()
+ while (!hasSeenError() && !mSawDecInputEOS && frameCnt < frameLimit) {
+ Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandleDecoder.getWork();
+ if (element != null) {
+ int bufferID = element.first;
+ MediaCodec.BufferInfo info = element.second;
+ if (info != null) {
+ // <id, info> corresponds to output callback. Handle it accordingly
+ dequeueDecoderOutput(bufferID, info);
+ } else {
+ // <id, null> corresponds to input callback. Handle it accordingly
+ enqueueDecoderInput(bufferID);
+ frameCnt++;
+ }
+ }
+ // check decoder EOS
+ if (mSawDecOutputEOS) mEncoder.signalEndOfInputStream();
+ // encoder output
+ if (mDecOutputCount - mEncOutputCount > mLatency) {
+ tryEncoderOutput(-1);
+ }
+ }
+ } else {
+ MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
+ while (!mSawDecInputEOS && frameCnt < frameLimit) {
+ // decoder input
+ int inputBufferId = mDecoder.dequeueInputBuffer(CodecTestBase.Q_DEQ_TIMEOUT_US);
+ if (inputBufferId != -1) {
+ enqueueDecoderInput(inputBufferId);
+ frameCnt++;
+ }
+ // decoder output
+ int outputBufferId =
+ mDecoder.dequeueOutputBuffer(outInfo, CodecTestBase.Q_DEQ_TIMEOUT_US);
+ if (outputBufferId >= 0) {
+ dequeueDecoderOutput(outputBufferId, outInfo);
+ }
+ // check decoder EOS
+ if (mSawDecOutputEOS) mEncoder.signalEndOfInputStream();
+ // encoder output
+ if (mDecOutputCount - mEncOutputCount > mLatency) {
+ tryEncoderOutput(-1);
+ }
+ }
+ }
+ }
+
+ MediaFormat setUpEncoderFormat(MediaFormat decoderFormat) {
+ MediaFormat encoderFormat = new MediaFormat();
+ encoderFormat.setString(MediaFormat.KEY_MIME, mMime);
+ encoderFormat.setInteger(MediaFormat.KEY_WIDTH,
+ decoderFormat.getInteger(MediaFormat.KEY_WIDTH));
+ encoderFormat.setInteger(MediaFormat.KEY_HEIGHT,
+ decoderFormat.getInteger(MediaFormat.KEY_HEIGHT));
+ encoderFormat.setInteger(MediaFormat.KEY_FRAME_RATE, mFrameRate);
+ encoderFormat.setInteger(MediaFormat.KEY_BIT_RATE, mBitrate);
+ encoderFormat.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 1.0f);
+ encoderFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
+ MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
+ encoderFormat.setInteger(MediaFormat.KEY_MAX_B_FRAMES, mMaxBFrames);
+ return encoderFormat;
+ }
+}
+
+class Transcode extends CodecTranscoderTestBase implements Callable<Double> {
+ private static final String LOG_TAG = Transcode.class.getSimpleName();
+
+ private final String mDecoderName;
+ private final String mEncoderName;
+ private final boolean mIsAsync;
+
+ Transcode(String mime, String testFile, String decoderName, String encoderName,
+ boolean isAsync) {
+ super(mime, testFile, 3000000, 30);
+ mDecoderName = decoderName;
+ mEncoderName = encoderName;
+ mIsAsync = isAsync;
+ }
+
+ public Double doTranscode() throws Exception {
+ MediaFormat decoderFormat = setUpSource(mTestFile);
+ mDecoder = MediaCodec.createByCodecName(mDecoderName);
+ MediaFormat encoderFormat = setUpEncoderFormat(decoderFormat);
+ mEncoder = MediaCodec.createByCodecName(mEncoderName);
+ mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+ configureCodec(decoderFormat, encoderFormat, mIsAsync, false);
+ mEncoder.start();
+ mDecoder.start();
+ long start = System.currentTimeMillis();
+ doWork(Integer.MAX_VALUE);
+ queueEOS();
+ waitForAllEncoderOutputs();
+ long end = System.currentTimeMillis();
+ mSurface.release();
+ mDecoder.stop();
+ mDecoder.release();
+ mEncoder.stop();
+ mEncoder.release();
+ mExtractor.release();
+ double fps = mEncOutputCount / ((end - start) / 1000.0);
+ Log.d(LOG_TAG, "Mime: " + mMime + " Decoder: " + mDecoderName + " Encoder: " +
+ mEncoderName + " Achieved fps: " + fps);
+ return fps;
+ }
+
+ @Override
+ public Double call() throws Exception {
+ return doTranscode();
+ }
+}
+
+class TranscodeLoad extends Transcode {
+ private final LoadStatus mLoadStatus;
+
+ private long mMaxPts;
+ private long mBasePts;
+
+ TranscodeLoad(String mime, String testFile, String decoderName, String encoderName,
+ LoadStatus loadStatus) {
+ super(mime, testFile, decoderName, encoderName, false);
+ mLoadStatus = loadStatus;
+ mMaxPts = 0;
+ mBasePts = 0;
+ }
+
+ @Override
+ void configureCodec(MediaFormat decFormat, MediaFormat encFormat, boolean isAsync,
+ boolean signalEOSWithLastFrame) {
+ decFormat.setInteger(MediaFormat.KEY_PRIORITY, 1);
+ encFormat.setInteger(MediaFormat.KEY_PRIORITY, 1);
+ resetContext(isAsync, signalEOSWithLastFrame);
+ mAsyncHandleEncoder.setCallBack(mEncoder, isAsync);
+ mEncoder.configure(encFormat, null, MediaCodec.CONFIGURE_FLAG_ENCODE, null);
+ if (mEncoder.getInputFormat().containsKey(MediaFormat.KEY_LATENCY)) {
+ mReviseLatency = true;
+ mLatency = mEncoder.getInputFormat().getInteger(MediaFormat.KEY_LATENCY);
+ }
+ mSurface = mEncoder.createInputSurface();
+ assertTrue("Surface is not valid", mSurface.isValid());
+ mAsyncHandleDecoder.setCallBack(mDecoder, isAsync);
+ mDecoder.configure(decFormat, mSurface, null, 0);
+ }
+
+ @Override
+ void enqueueDecoderInput(int bufferIndex) {
+ if (mExtractor.getSampleSize() < 0) {
+ enqueueDecoderEOS(bufferIndex);
+ } else {
+ ByteBuffer inputBuffer = mDecoder.getInputBuffer(bufferIndex);
+ int size = mExtractor.readSampleData(inputBuffer, 0);
+ long pts = mExtractor.getSampleTime();
+ mMaxPts = Math.max(mMaxPts, mBasePts + pts);
+ int extractorFlags = mExtractor.getSampleFlags();
+ int codecFlags = 0;
+ if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
+ codecFlags |= MediaCodec.BUFFER_FLAG_KEY_FRAME;
+ }
+ mDecoder.queueInputBuffer(bufferIndex, 0, size, mBasePts + pts, codecFlags);
+ if (size > 0 && (codecFlags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+ mDecInputCount++;
+ }
+ if (!mExtractor.advance() && !mLoadStatus.isLoadFinished()) {
+ mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+ mBasePts = mMaxPts + 1000000L;
+ }
+ }
+ }
+}
+
+class LoadStatus {
+ private boolean mLoadFinished;
+
+ public LoadStatus() { mLoadFinished = false; }
+
+ public synchronized void setLoadFinished() { mLoadFinished = true; }
+
+ public synchronized boolean isLoadFinished() { return mLoadFinished; }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/DecodeExtractedSamplesTestBase.java b/tests/mediapc/src/android/mediapc/cts/DecodeExtractedSamplesTestBase.java
new file mode 100644
index 0000000..f47152e
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/DecodeExtractedSamplesTestBase.java
@@ -0,0 +1,152 @@
+/*
+ * 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 android.media.MediaCodec;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.view.Surface;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+public class DecodeExtractedSamplesTestBase extends CodecDecoderTestBase {
+ private static final long EACH_FRAME_TIME_INTERVAL_US = 1000000 / 60;
+
+ final String[] mTestFiles;
+ final boolean mIsAsync;
+
+ long mFrameDropCount;
+ ByteBuffer mBuff;
+ ArrayList<MediaCodec.BufferInfo> mBufferInfos;
+
+ private long mMaxPtsUs;
+ private long mRenderStartTimeUs;
+
+ DecodeExtractedSamplesTestBase(String mime, String[] testFiles, Surface surface,
+ boolean isAsync) {
+ super(mime, null);
+ mTestFiles = testFiles;
+ mSurface = surface;
+ mIsAsync = isAsync;
+ mMaxPtsUs = 0;
+ mFrameDropCount = 0;
+ mBufferInfos = new ArrayList<>();
+ }
+
+ private MediaFormat createInputList(MediaFormat format, ByteBuffer buffer,
+ ArrayList<MediaCodec.BufferInfo> list, int offset, long ptsOffset) {
+ if (hasCSD(format)) {
+ MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
+ bufferInfo.offset = offset;
+ bufferInfo.size = 0;
+ bufferInfo.presentationTimeUs = 0;
+ bufferInfo.flags = MediaCodec.BUFFER_FLAG_CODEC_CONFIG;
+ for (int i = 0; ; i++) {
+ String csdKey = "csd-" + i;
+ if (format.containsKey(csdKey)) {
+ ByteBuffer csdBuffer = format.getByteBuffer(csdKey);
+ bufferInfo.size += csdBuffer.limit();
+ buffer.put(csdBuffer);
+ format.removeKey(csdKey);
+ } else break;
+ }
+ list.add(bufferInfo);
+ offset += bufferInfo.size;
+ }
+ while (true) {
+ MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
+ bufferInfo.size = mExtractor.readSampleData(buffer, offset);
+ if (bufferInfo.size < 0) break;
+ bufferInfo.offset = offset;
+ bufferInfo.presentationTimeUs = ptsOffset + mExtractor.getSampleTime();
+ mMaxPtsUs = Math.max(mMaxPtsUs, bufferInfo.presentationTimeUs);
+ int flags = mExtractor.getSampleFlags();
+ bufferInfo.flags = 0;
+ if ((flags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
+ bufferInfo.flags |= MediaCodec.BUFFER_FLAG_KEY_FRAME;
+ }
+ list.add(bufferInfo);
+ mExtractor.advance();
+ offset += bufferInfo.size;
+ }
+ buffer.clear();
+ buffer.position(offset);
+ return format;
+ }
+
+ public ArrayList<MediaFormat> setUpSourceFiles() throws Exception {
+ ArrayList<MediaFormat> formats = new ArrayList<>();
+ for (String file : mTestFiles) {
+ formats.add(setUpSource(file));
+ mExtractor.release();
+ }
+ int totalSize = 0;
+ for (String srcFile : mTestFiles) {
+ File file = new File(mInpPrefix + srcFile);
+ totalSize += (int) file.length();
+ }
+ totalSize <<= 1;
+ long ptsOffset = 0;
+ int buffOffset = 0;
+ mBuff = ByteBuffer.allocate(totalSize);
+ for (String file : mTestFiles) {
+ formats.add(createInputList(setUpSource(file), mBuff, mBufferInfos, buffOffset,
+ ptsOffset));
+ mExtractor.release();
+ ptsOffset = mMaxPtsUs + 1000000L;
+ buffOffset = (mBufferInfos.get(mBufferInfos.size() - 1).offset) +
+ (mBufferInfos.get(mBufferInfos.size() - 1).size);
+ }
+ return formats;
+ }
+
+ private long getRenderTimeUs(int frameIndex) {
+ return mRenderStartTimeUs + frameIndex * EACH_FRAME_TIME_INTERVAL_US;
+ }
+
+ @Override
+ void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ mSawOutputEOS = true;
+ }
+ long nowUs = System.nanoTime() / 1000;
+ if (mOutputCount == 0) {
+ mRenderStartTimeUs = nowUs;
+ mCodec.releaseOutputBuffer(bufferIndex, true);
+ } else if (nowUs > getRenderTimeUs(mOutputCount + 1)) {
+ mFrameDropCount++;
+ mCodec.releaseOutputBuffer(bufferIndex, false);
+ } else if (nowUs > getRenderTimeUs(mOutputCount)) {
+ mCodec.releaseOutputBuffer(bufferIndex, true);
+ } else {
+ if ((getRenderTimeUs(mOutputCount) - nowUs) > (EACH_FRAME_TIME_INTERVAL_US / 2)) {
+ try {
+ Thread.sleep(((getRenderTimeUs(mOutputCount) - nowUs) -
+ (EACH_FRAME_TIME_INTERVAL_US / 2)) / 1000);
+ } catch (InterruptedException e) {
+ // Do nothing.
+ }
+ }
+ mCodec.releaseOutputBuffer(bufferIndex, true);
+ }
+ if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+ mOutputCount++;
+ }
+ }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/EncoderInitializationLatencyTest.java b/tests/mediapc/src/android/mediapc/cts/EncoderInitializationLatencyTest.java
new file mode 100644
index 0000000..0312ebc
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/EncoderInitializationLatencyTest.java
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.mediapc.cts;
+
+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.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 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.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+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.assumeTrue;
+
+@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_MS = 30;
+ private static final int MAX_VIDEOENC_INITIALIZATION_LATENCY_MS = 40;
+ 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 {
+ AVC_DECODER_NAME = selectHardwareCodecs(AVC, null, null, false).get(0);
+ AVC_ENCODER_NAME = selectHardwareCodecs(AVC, null, null, true).get(0);
+ }
+
+ 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 {
+ assumeTrue("Test requires performance class.", Utils.isPerfClass());
+ 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);
+
+ 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;
+ }
+
+ 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;
+ }
+
+ @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();
+ 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)
+ 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 300ms.
+ Thread.sleep(300);
+ 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;
+ }
+ }
+
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ public void testInitializationLatency() throws Exception {
+ int maxCodecInitializationLatencyMs = mMime.startsWith("audio/") ?
+ MAX_AUDIOENC_INITIALIZATION_LATENCY_MS : MAX_VIDEOENC_INITIALIZATION_LATENCY_MS;
+ for (int i = 0; i < 5; i++) {
+ for (boolean isAsync : boolStates) {
+ EncoderInitializationLatency encoderInitializationLatency =
+ new EncoderInitializationLatency(mMime, mEncoderName, isAsync);
+ long encoderInitializationLatencyMs = encoderInitializationLatency
+ .calculateEncoderInitializationLatency();
+ String errorLog = String.format("CodecInitialization latency for mime: %s, " +
+ "Encoder: %s, Iteration: %d, mode: %s is not as expected. act/exp: " +
+ " %d/%d", mMime, mEncoderName, i, (isAsync ? "async" : "sync"),
+ encoderInitializationLatencyMs, maxCodecInitializationLatencyMs);
+ assertTrue(errorLog,
+ encoderInitializationLatencyMs <= maxCodecInitializationLatencyMs);
+ }
+ }
+ }
+}
+
+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() {
+ 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 {
+ format.setInteger(MediaFormat.KEY_WIDTH, 1920);
+ format.setInteger(MediaFormat.KEY_HEIGHT, 1080);
+ format.setInteger(MediaFormat.KEY_FRAME_RATE, mFrameRate);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, 8000000);
+ 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 step1TimeMs; // Time of (create + configure)
+ long step2TimeMs; // Time of (create + configure + start)
+ long step3TimeMs = 0; // Time of (create + configure + start + first frame to enqueue)
+ long step4TimeMs = 0; // Time of (create + configure + start + first frame to dequeue)
+ long start = System.currentTimeMillis();
+ mCodec = MediaCodec.createByCodecName(mEncoderName);
+ resetContext(mIsAsync, false);
+ mAsyncHandle.setCallBack(mCodec, mIsAsync);
+ mCodec.configure(format, null, MediaCodec.CONFIGURE_FLAG_ENCODE, null);
+ step1TimeMs = System.currentTimeMillis() - start;
+ mCodec.start();
+ step2TimeMs = System.currentTimeMillis() - start;
+ if (mIsAsync) {
+ 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) {
+ step4TimeMs = System.currentTimeMillis() - start;
+ dequeueOutput(bufferID, info);
+ break;
+ } else {
+ if (step3TimeMs == 0) step3TimeMs = System.currentTimeMillis() - start;
+ enqueueInput(bufferID);
+ }
+ }
+ }
+ } else {
+ while (!mSawOutputEOS) {
+ if (!mSawInputEOS) {
+ int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
+ if (inputBufferId > 0) {
+ if (step3TimeMs == 0) step3TimeMs = System.currentTimeMillis() - start;
+ enqueueInput(inputBufferId);
+ }
+ }
+ int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
+ if (outputBufferId >= 0) {
+ step4TimeMs = System.currentTimeMillis() - start;
+ dequeueOutput(outputBufferId, outInfo);
+ break;
+ }
+ }
+ }
+ queueEOS();
+ waitForAllOutputs();
+ mCodec.stop();
+ mCodec.release();
+ Log.d(LOG_TAG, "Encode mMime: " + mMime + " Encoder: " + mEncoderName +
+ " Time for (create + configure): " + step1TimeMs);
+ Log.d(LOG_TAG, "Encode mMime: " + mMime + " Encoder: " + mEncoderName +
+ " Time for (create + configure + start): " + step2TimeMs);
+ Log.d(LOG_TAG, "Encode mMime: " + mMime + " Encoder: " + mEncoderName +
+ " Time for (create + configure + start + first frame to enqueue): " + step3TimeMs);
+ Log.d(LOG_TAG, "Encode mMime: " + mMime + " Encoder: " + mEncoderName +
+ " Time for (create + configure + start + first frame to dequeue): " + step4TimeMs);
+ return step1TimeMs;
+ }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/FrameDropTest.java b/tests/mediapc/src/android/mediapc/cts/FrameDropTest.java
new file mode 100644
index 0000000..10cc040
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/FrameDropTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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 android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.view.Surface;
+
+import androidx.test.filters.LargeTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import static android.mediapc.cts.FrameDropTestBase.DECODE_30S;
+import static android.mediapc.cts.FrameDropTestBase.MAX_FRAME_DROP_FOR_30S;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(Parameterized.class)
+public class FrameDropTest extends FrameDropTestBase {
+ private static final String LOG_TAG = FrameDropTest.class.getSimpleName();
+
+ public FrameDropTest(String mimeType, String decoderName, boolean isAsync) {
+ super(mimeType, decoderName, isAsync);
+ }
+
+ @Parameterized.Parameters(name = "{index}({0}_{1}_{2})")
+ public static Collection<Object[]> inputParams() {
+ return prepareArgumentsList(null);
+ }
+
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ public void testDecodeToSurface() throws Exception {
+ DecodeToSurfaceFrameDrop decodeToSurfaceFrameDrop = new DecodeToSurfaceFrameDrop(mMime,
+ m1080pTestFiles.get(mMime), mDecoderName, mSurface, mIsAsync);
+ decodeToSurfaceFrameDrop.doDecodeAndCalculateFrameDrop();
+ }
+}
+
+class DecodeToSurfaceFrameDrop extends DecodeExtractedSamplesTestBase {
+ private final String mDecoderName;
+
+ private long mBasePts;
+ private long mMaxPts;
+ private long mDecodeStartTimeMs;
+ private int mSampleIndex;
+
+ DecodeToSurfaceFrameDrop(String mime, String testFile, String decoderName, Surface surface,
+ boolean isAsync) {
+ super(mime, new String[]{testFile}, surface, isAsync);
+ mDecoderName = decoderName;
+ mBasePts = 0;
+ mMaxPts = 0;
+ mSampleIndex = 0;
+ }
+
+ public void doDecodeAndCalculateFrameDrop() throws Exception {
+ ArrayList<MediaFormat> formats = setUpSourceFiles();
+ mCodec = MediaCodec.createByCodecName(mDecoderName);
+ configureCodec(formats.get(0), mIsAsync, false, false);
+ mCodec.start();
+ mDecodeStartTimeMs = System.currentTimeMillis();
+ doWork(Integer.MAX_VALUE);
+ queueEOS();
+ waitForAllOutputs();
+ mCodec.stop();
+ mCodec.release();
+ assertTrue("FrameDrop count for mime: " + mMime + " decoder: " + mDecoderName +
+ " is not as expected. act/exp: " + mFrameDropCount + "/" + MAX_FRAME_DROP_FOR_30S,
+ mFrameDropCount <= MAX_FRAME_DROP_FOR_30S);
+ }
+
+ @Override
+ void enqueueInput(int bufferIndex) {
+ if (mSampleIndex == mBufferInfos.size()) {
+ enqueueEOS(bufferIndex);
+ } else {
+ MediaCodec.BufferInfo info = mBufferInfos.get(mSampleIndex++);
+ if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+ ByteBuffer dstBuf = mCodec.getInputBuffer(bufferIndex);
+ dstBuf.put(mBuff.array(), info.offset, info.size);
+ mInputCount++;
+ }
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ mSawInputEOS = true;
+ }
+ long pts = info.presentationTimeUs;
+ mMaxPts = Math.max(mMaxPts, mBasePts + pts);
+ mCodec.queueInputBuffer(bufferIndex, 0, info.size, mBasePts + pts, info.flags);
+ if (mSampleIndex == mBufferInfos.size() &&
+ // Decode for at least 30s
+ (System.currentTimeMillis() - mDecodeStartTimeMs < DECODE_30S)) {
+ mSampleIndex = 0;
+ mBasePts = mMaxPts + 1000000L;
+ }
+ }
+ }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/FrameDropTestBase.java b/tests/mediapc/src/android/mediapc/cts/FrameDropTestBase.java
new file mode 100644
index 0000000..631fe52
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/FrameDropTestBase.java
@@ -0,0 +1,195 @@
+/*
+ * 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 android.media.MediaFormat;
+import android.view.Surface;
+
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static android.mediapc.cts.CodecTestBase.selectCodecs;
+import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+public class FrameDropTestBase {
+ private static final String LOG_TAG = FrameDropTestBase.class.getSimpleName();
+ static final boolean[] boolStates = {false, true};
+ static final String AVC = MediaFormat.MIMETYPE_VIDEO_AVC;
+ static final String HEVC = MediaFormat.MIMETYPE_VIDEO_HEVC;
+ static final String VP8 = MediaFormat.MIMETYPE_VIDEO_VP8;
+ static final String VP9 = MediaFormat.MIMETYPE_VIDEO_VP9;
+ static final String AV1 = MediaFormat.MIMETYPE_VIDEO_AV1;
+ static final String AAC = MediaFormat.MIMETYPE_AUDIO_AAC;
+ static final String AAC_LOAD_FILE_NAME = "bbb_1c_128kbps_aac_audio.mp4";
+ static final String AVC_LOAD_FILE_NAME = "bbb_1280x720_3mbps_30fps_avc.mp4";
+ static final long DECODE_30S = 30000; // In ms
+ static final long MAX_FRAME_DROP_FOR_30S = 3;
+
+ final String mMime;
+ final String mDecoderName;
+ final boolean mIsAsync;
+ Surface mSurface;
+
+ private LoadStatus mLoadStatus = null;
+ private Thread mTranscodeLoadThread = null;
+ private Thread mAudioPlaybackLoadThread = null;
+ private Exception mTranscodeLoadException = null;
+ private Exception mAudioPlaybackLoadException = null;
+
+ static String AVC_DECODER_NAME;
+ static String AVC_ENCODER_NAME;
+ static String AAC_DECODER_NAME;
+ static Map<String, String> m540pTestFiles = new HashMap<>();
+ static Map<String, String> m1080pTestFiles = new HashMap<>();
+ static {
+ AVC_DECODER_NAME = selectHardwareCodecs(AVC, null, null, false).get(0);
+ AVC_ENCODER_NAME = selectHardwareCodecs(AVC, null, null, true).get(0);
+ AAC_DECODER_NAME = selectCodecs(AAC, null, null, false).get(0);
+ }
+ static {
+ m540pTestFiles.put(AVC, "bbb_960x540_3mbps_60fps_avc.mp4");
+ m540pTestFiles.put(HEVC, "bbb_960x540_3mbps_60fps_hevc.mp4");
+ m540pTestFiles.put(VP8, "bbb_960x540_3mbps_60fps_vp8.webm");
+ m540pTestFiles.put(VP9, "bbb_960x540_3mbps_60fps_vp9.webm");
+ m540pTestFiles.put(AV1, "bbb_960x540_3mbps_60fps_av1.mp4");
+ }
+ static {
+ m1080pTestFiles.put(AVC, "bbb_1920x1080_8mbps_60fps_avc.mp4");
+ m1080pTestFiles.put(HEVC, "bbb_1920x1080_8mbps_60fps_hevc.mp4");
+ m1080pTestFiles.put(VP8, "bbb_1920x1080_8mbps_60fps_vp8.webm");
+ m1080pTestFiles.put(VP9, "bbb_1920x1080_8mbps_60fps_vp9.webm");
+ m1080pTestFiles.put(AV1, "bbb_1920x1080_8mbps_60fps_av1.mp4");
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ assumeTrue("Test requires performance class.", Utils.isPerfClass());
+ createSurface();
+ startLoad();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ stopLoad();
+ releaseSurface();
+ }
+
+ @Rule
+ public ActivityTestRule<TestActivity> mActivityRule =
+ new ActivityTestRule<>(TestActivity.class);
+
+ public FrameDropTestBase(String mimeType, String decoderName, boolean isAsync) {
+ mMime = mimeType;
+ mDecoderName = decoderName;
+ mIsAsync = isAsync;
+ }
+
+ static List<Object[]> prepareArgumentsList(String[] features) {
+ final List<Object[]> argsList = new ArrayList<>();
+ final String[] mimesList = new String[] {AVC, HEVC, VP8, VP9, AV1};
+ for (String mime : mimesList) {
+ ArrayList<String> listOfDecoders = selectHardwareCodecs(mime, null, features, false);
+ for (String decoder : listOfDecoders) {
+ for (boolean isAsync : boolStates) {
+ argsList.add(new Object[]{mime, decoder, isAsync});
+ }
+ }
+ }
+ return argsList;
+ }
+
+ 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());
+ // As we display 1920x1080 and 960x540 only which are of same aspect ratio, we will
+ // be setting screen params to 1920x1080
+ mActivityRule.getActivity().setScreenParams(1920, 1080, true);
+ }
+
+ private void releaseSurface() {
+ if (mSurface != null) {
+ mSurface.release();
+ mSurface = null;
+ }
+ }
+
+ private Thread createTranscodeLoad() {
+ Thread transcodeLoadThread = new Thread(() -> {
+ try {
+ TranscodeLoad transcodeLoad = new TranscodeLoad(AVC, AVC_LOAD_FILE_NAME,
+ AVC_DECODER_NAME, AVC_ENCODER_NAME, mLoadStatus);
+ transcodeLoad.doTranscode();
+ } catch (Exception e) {
+ mTranscodeLoadException = e;
+ }
+ });
+ return transcodeLoadThread;
+ }
+
+ private Thread createAudioPlaybackLoad() {
+ Thread audioPlaybackLoadThread = new Thread(() -> {
+ try {
+ AudioPlaybackLoad audioPlaybackLoad = new AudioPlaybackLoad(AAC, AAC_LOAD_FILE_NAME,
+ AAC_DECODER_NAME, mLoadStatus);
+ audioPlaybackLoad.doDecodeAndPlayback();
+ } catch (Exception e) {
+ mAudioPlaybackLoadException = e;
+ }
+ });
+ return audioPlaybackLoadThread;
+ }
+
+ private void startLoad() {
+ // TODO: b/183671436
+ // Start Transcode load (Decoder(720p) + Encoder(720p))
+ mLoadStatus = new LoadStatus();
+ mTranscodeLoadThread = createTranscodeLoad();
+ mTranscodeLoadThread.start();
+ // Start 128kbps AAC audio playback
+ mAudioPlaybackLoadThread = createAudioPlaybackLoad();
+ mAudioPlaybackLoadThread.start();
+ }
+
+ private void stopLoad() throws Exception {
+ if (mLoadStatus != null) {
+ mLoadStatus.setLoadFinished();
+ mLoadStatus = null;
+ }
+ if (mTranscodeLoadThread != null) {
+ mTranscodeLoadThread.join();
+ mTranscodeLoadThread = null;
+ }
+ if (mAudioPlaybackLoadThread != null) {
+ mAudioPlaybackLoadThread.join();
+ mAudioPlaybackLoadThread = null;
+ }
+ if (mTranscodeLoadException != null) throw mTranscodeLoadException;
+ if (mAudioPlaybackLoadException != null) throw mAudioPlaybackLoadException;
+ }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java b/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java
new file mode 100644
index 0000000..86104ce
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/MultiCodecPerfTestBase.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.mediapc.cts;
+
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint;
+import android.media.MediaFormat;
+import android.util.Pair;
+
+import org.junit.Before;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static android.mediapc.cts.CodecTestBase.selectHardwareCodecs;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+public class MultiCodecPerfTestBase {
+ private static final String LOG_TAG = MultiCodecPerfTestBase.class.getSimpleName();
+ static final boolean[] boolStates = {true, false};
+ static final int REQUIRED_MIN_CONCURRENT_INSTANCES = 6;
+ static final String[] mMimeList = new String[] {
+ MediaFormat.MIMETYPE_VIDEO_AVC,
+ MediaFormat.MIMETYPE_VIDEO_HEVC,
+ MediaFormat.MIMETYPE_VIDEO_VP8,
+ MediaFormat.MIMETYPE_VIDEO_VP9,
+ MediaFormat.MIMETYPE_VIDEO_AV1
+ };
+ static Map<String, String> mTestFiles = new HashMap<>();
+ static {
+ mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AVC, "bbb_1280x720_3mbps_30fps_avc.mp4");
+ mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_HEVC, "bbb_1280x720_3mbps_30fps_hevc.mp4");
+ mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_VP8, "bbb_1280x720_3mbps_30fps_vp8.webm");
+ mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_1280x720_3mbps_30fps_vp9.webm");
+ mTestFiles.put(MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_1280x720_3mbps_30fps_av1.mp4");
+ }
+
+ String mMime;
+ String mTestFile;
+ final boolean mIsAsync;
+
+ double mMaxFrameRate;
+
+ @Before
+ public void isPerformanceClass() {
+ assumeTrue("Test requires performance class.", Utils.isPerfClass());
+ }
+
+ public MultiCodecPerfTestBase(String mime, String testFile, boolean isAsync) {
+ mMime = mime;
+ mTestFile = testFile;
+ mIsAsync = isAsync;
+ }
+
+ public static ArrayList<String> getHardwareCodecsFor720p(String mime, boolean isEncoder) {
+ MediaFormat fmt = MediaFormat.createVideoFormat(mime, 1280, 720);
+ fmt.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
+ ArrayList<MediaFormat> formatsList = new ArrayList<>();
+ formatsList.add(fmt);
+ return selectHardwareCodecs(mime, formatsList, null, isEncoder);
+ }
+
+ public int checkAndGetMaxSupportedInstancesFor720p(
+ ArrayList<Pair<String, String>> mimeCodecPairs) throws IOException {
+ int[] maxInstances = new int[mimeCodecPairs.size()];
+ int[] maxFrameRates = new int[mimeCodecPairs.size()];
+ int[] maxMacroBlockRates = new int[mimeCodecPairs.size()];
+ int loopCount = 0;
+ for (Pair<String, String> mimeCodecPair : mimeCodecPairs) {
+ MediaCodec codec = MediaCodec.createByCodecName(mimeCodecPair.second);
+ MediaCodecInfo.CodecCapabilities cap = codec.getCodecInfo()
+ .getCapabilitiesForType(mimeCodecPair.first);
+ List<PerformancePoint> pps = cap.getVideoCapabilities().getSupportedPerformancePoints();
+ assertTrue(pps.size() > 0);
+ maxInstances[loopCount] = cap.getMaxSupportedInstances();
+ PerformancePoint PP720p = new PerformancePoint(1280, 720, 180);
+ maxMacroBlockRates[loopCount] = 0;
+ boolean supports720p180Performance = false;
+ for (PerformancePoint pp : pps) {
+ if(pp.covers(PP720p)) {
+ supports720p180Performance = true;
+ if (pp.getMaxMacroBlockRate() > maxMacroBlockRates[loopCount]) {
+ maxMacroBlockRates[loopCount] = (int) pp.getMaxMacroBlockRate();
+ maxFrameRates[loopCount] = pp.getMaxFrameRate();
+ }
+ }
+ }
+ codec.release();
+ assertTrue("Codec " + mimeCodecPair.second + " doesn't support 720p 180 " +
+ "performance point", supports720p180Performance);
+ loopCount++;
+ }
+ Arrays.sort(maxInstances);
+ Arrays.sort(maxFrameRates);
+ Arrays.sort(maxMacroBlockRates);
+ int minOfMaxInstances = maxInstances[0];
+ int minOfMaxFrameRates = maxFrameRates[0];
+ int minOfMaxMacroBlockRates = maxMacroBlockRates[0];
+ mMaxFrameRate = minOfMaxFrameRates;
+ // Calculate how many 720p 30fps max instances it can support from it's mMaxFrameRate
+ // amd maxMacroBlockRate. (720p is 3,600 macro blocks assuming 16x16 macroblocks)
+ return Math.min(minOfMaxInstances, Math.min((int) (minOfMaxFrameRates / 30.0),
+ (int) (minOfMaxMacroBlockRates / 3600.0 / 30)));
+ }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java
new file mode 100644
index 0000000..6d6d003
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPairPerfTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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 android.util.Pair;
+
+import androidx.test.filters.LargeTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import static org.junit.Assert.assertTrue;
+
+@RunWith(Parameterized.class)
+public class MultiDecoderPairPerfTest extends MultiCodecPerfTestBase {
+ private static final String LOG_TAG = MultiDecoderPairPerfTest.class.getSimpleName();
+
+ private final Pair<String, String> mFirstPair;
+ private final Pair<String, String> mSecondPair;
+
+ public MultiDecoderPairPerfTest(Pair<String, String> firstPair, Pair<String, String> secondPair,
+ boolean isAsync) {
+ super(null, null, isAsync);
+ mFirstPair = firstPair;
+ mSecondPair = secondPair;
+ }
+
+ @Parameterized.Parameters(name = "{index}({0}_{1}_{2})")
+ public static Collection<Object[]> inputParams() {
+ // Prepares the params list with the supported Hardware decoders in the device
+ final List<Object[]> argsList = new ArrayList<>();
+ ArrayList<Pair<String, String>> mimeTypeDecoderPairs = new ArrayList<>();
+ for (String mime : mMimeList) {
+ ArrayList<String> listOfDecoders = getHardwareCodecsFor720p(mime, false);
+ for (String decoder : listOfDecoders) {
+ mimeTypeDecoderPairs.add(Pair.create(mime, decoder));
+ }
+ }
+ for (int i = 0; i < mimeTypeDecoderPairs.size(); i++) {
+ for (int j = i + 1; j < mimeTypeDecoderPairs.size(); j++) {
+ Pair<String, String> pair1 = mimeTypeDecoderPairs.get(i);
+ Pair<String, String> pair2 = mimeTypeDecoderPairs.get(j);
+ for (boolean isAsync : boolStates) {
+ argsList.add(new Object[]{pair1, pair2, isAsync});
+ }
+ }
+ }
+ return argsList;
+ }
+
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ public void test720p() throws Exception {
+ ArrayList<Pair<String, String>> mimeDecoderPairs = new ArrayList<>();
+ mimeDecoderPairs.add(mFirstPair);
+ mimeDecoderPairs.add(mSecondPair);
+ int maxInstances = checkAndGetMaxSupportedInstancesFor720p(mimeDecoderPairs);
+ int secondPairInstances = maxInstances / 2;
+ int firstPairInstances = maxInstances - secondPairInstances;
+ ExecutorService pool = Executors.newFixedThreadPool(maxInstances);
+ List<Decode> testList = new ArrayList<>();
+ for (int i = 0; i < firstPairInstances; i++) {
+ testList.add(new Decode(mFirstPair.first, mTestFiles.get(mFirstPair.first),
+ mFirstPair.second, mIsAsync));
+ }
+ for (int i = 0; i < secondPairInstances; i++) {
+ testList.add(new Decode(mSecondPair.first, mTestFiles.get(mSecondPair.first),
+ mSecondPair.second, mIsAsync));
+ }
+ List<Future<Double>> resultList = pool.invokeAll(testList);
+ double achievedFrameRate = 0.0;
+ for (Future<Double> result : resultList) {
+ achievedFrameRate += result.get();
+ }
+ assertTrue("Unable to achieve the maxFrameRate supported. act/exp: " + achievedFrameRate
+ + "/" + mMaxFrameRate, achievedFrameRate >= mMaxFrameRate);
+ }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java
new file mode 100644
index 0000000..dbaca7b
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/MultiDecoderPerfTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.mediapc.cts;
+
+import android.util.Pair;
+
+import androidx.test.filters.LargeTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import static org.junit.Assert.assertTrue;
+
+@RunWith(Parameterized.class)
+public class MultiDecoderPerfTest extends MultiCodecPerfTestBase {
+ private static final String LOG_TAG = MultiDecoderPerfTest.class.getSimpleName();
+
+ private final String mDecoderName;
+
+ public MultiDecoderPerfTest(String mimeType, String testFile, String decoderName,
+ boolean isAsync) {
+ super(mimeType, testFile, isAsync);
+ mDecoderName = decoderName;
+ }
+
+ @Parameterized.Parameters(name = "{index}({0}_{2}_{3})")
+ public static Collection<Object[]> inputParams() {
+ // Prepares the params list with the supported Hardware decoders in the device
+ final List<Object[]> argsList = new ArrayList<>();
+ for (String mime : mMimeList) {
+ ArrayList<String> listOfDecoders = getHardwareCodecsFor720p(mime, false);
+ for (String decoder : listOfDecoders) {
+ for (boolean isAsync : boolStates) {
+ argsList.add(new Object[]{mime, mTestFiles.get(mime), decoder, isAsync});
+ }
+ }
+ }
+ return argsList;
+ }
+
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ public void test720p() throws Exception {
+ ArrayList<Pair<String, String>> mimeDecoderPairs = new ArrayList<>();
+ mimeDecoderPairs.add(Pair.create(mMime, mDecoderName));
+ int maxInstances = checkAndGetMaxSupportedInstancesFor720p(mimeDecoderPairs);
+ assertTrue("Decoder " + mDecoderName + " unable to support minimum concurrent " +
+ "instances. act/exp: " + maxInstances + "/" + REQUIRED_MIN_CONCURRENT_INSTANCES,
+ maxInstances >= REQUIRED_MIN_CONCURRENT_INSTANCES);
+ ExecutorService pool = Executors.newFixedThreadPool(maxInstances);
+ List<Decode> testList = new ArrayList<>();
+ for (int i = 0; i < maxInstances; i++) {
+ testList.add(new Decode(mMime, mTestFile, mDecoderName, mIsAsync));
+ }
+ List<Future<Double>> resultList = pool.invokeAll(testList);
+ double achievedFrameRate = 0.0;
+ for (Future<Double> result : resultList) {
+ achievedFrameRate += result.get();
+ }
+ assertTrue("Unable to achieve the maxFrameRate supported. act/exp: " + achievedFrameRate
+ + "/" + mMaxFrameRate, achievedFrameRate >= mMaxFrameRate);
+ }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java
new file mode 100644
index 0000000..d732c82
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPairPerfTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.mediapc.cts;
+
+import android.util.Pair;
+
+import androidx.test.filters.LargeTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+@RunWith(Parameterized.class)
+public class MultiEncoderPairPerfTest extends MultiCodecPerfTestBase {
+ private static final String LOG_TAG = MultiEncoderPairPerfTest.class.getSimpleName();
+
+ private final Pair<String, String> mFirstPair;
+ private final Pair<String, String> mSecondPair;
+
+ public MultiEncoderPairPerfTest(Pair<String, String> firstPair, Pair<String, String> secondPair,
+ boolean isAsync) {
+ super(null, null, isAsync);
+ mFirstPair = firstPair;
+ mSecondPair = secondPair;
+ }
+
+ @Parameterized.Parameters(name = "{index}({0}_{1}_{2})")
+ public static Collection<Object[]> inputParams() {
+ // Prepares the params list with the supported Hardware encoders in the device
+ final List<Object[]> argsList = new ArrayList<>();
+ ArrayList<Pair<String, String>> mimeTypeEncoderPairs = new ArrayList<>();
+ for (String mime : mMimeList) {
+ ArrayList<String> listOfEncoders = getHardwareCodecsFor720p(mime, true);
+ for (String encoder : listOfEncoders) {
+ mimeTypeEncoderPairs.add(Pair.create(mime, encoder));
+ }
+ }
+ for (int i = 0; i < mimeTypeEncoderPairs.size(); i++) {
+ for (int j = i + 1; j < mimeTypeEncoderPairs.size(); j++) {
+ Pair<String, String> pair1 = mimeTypeEncoderPairs.get(i);
+ Pair<String, String> pair2 = mimeTypeEncoderPairs.get(j);
+ for (boolean isAsync : boolStates) {
+ argsList.add(new Object[]{pair1, pair2, isAsync});
+ }
+ }
+ }
+ return argsList;
+ }
+
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ public void test720p() throws Exception {
+ ArrayList<Pair<String, String>> mimeEncoderPairs = new ArrayList<>();
+ mimeEncoderPairs.add(mFirstPair);
+ mimeEncoderPairs.add(mSecondPair);
+ int maxInstances = checkAndGetMaxSupportedInstancesFor720p(mimeEncoderPairs);
+ int secondPairInstances = maxInstances / 2;
+ int firstPairInstances = maxInstances - secondPairInstances;
+ ExecutorService pool = Executors.newFixedThreadPool(maxInstances);
+ List<Encode> testList = new ArrayList<>();
+ for (int i = 0; i < firstPairInstances; i++) {
+ testList.add(new Encode(mFirstPair.first, mFirstPair.second, mIsAsync));
+ }
+ for (int i = 0; i < secondPairInstances; i++) {
+ testList.add(new Encode(mSecondPair.first, mSecondPair.second, mIsAsync));
+ }
+ List<Future<Double>> resultList = pool.invokeAll(testList);
+ double achievedFrameRate = 0.0;
+ for (Future<Double> result : resultList) {
+ achievedFrameRate += result.get();
+ }
+ // Achieved frame rate is not compared as this test runs in byte buffer mode.
+ }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java
new file mode 100644
index 0000000..8fb78b7
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/MultiEncoderPerfTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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 android.util.Pair;
+
+import androidx.test.filters.LargeTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import static org.junit.Assert.assertTrue;
+
+@RunWith(Parameterized.class)
+public class MultiEncoderPerfTest extends MultiCodecPerfTestBase {
+ private static final String LOG_TAG = MultiEncoderPerfTest.class.getSimpleName();
+
+ private final String mEncoderName;
+
+ public MultiEncoderPerfTest(String mimeType, String encoderName, boolean isAsync) {
+ super(mimeType, null, isAsync);
+ mEncoderName = encoderName;
+ }
+
+ @Parameterized.Parameters(name = "{index}({0}_{1}_{2})")
+ public static Collection<Object[]> inputParams() {
+ // Prepares the params list with the supported Hardware encoders in the device
+ final List<Object[]> argsList = new ArrayList<>();
+ for (String mime : mMimeList) {
+ ArrayList<String> listOfEncoders = getHardwareCodecsFor720p(mime, true);
+ for (String encoder : listOfEncoders) {
+ for (boolean isAsync : boolStates) {
+ argsList.add(new Object[]{mime, encoder, isAsync});
+ }
+ }
+ }
+ return argsList;
+ }
+
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ public void test720p() throws Exception {
+ ArrayList<Pair<String, String>> mimeEncoderPairs = new ArrayList<>();
+ mimeEncoderPairs.add(Pair.create(mMime, mEncoderName));
+ int maxInstances = checkAndGetMaxSupportedInstancesFor720p(mimeEncoderPairs);
+ assertTrue("Encoder " + mEncoderName + " unable to support minimum concurrent " +
+ "instances. act/exp: " + maxInstances + "/" + REQUIRED_MIN_CONCURRENT_INSTANCES,
+ maxInstances >= REQUIRED_MIN_CONCURRENT_INSTANCES);
+ ExecutorService pool = Executors.newFixedThreadPool(maxInstances);
+ List<Encode> testList = new ArrayList<>();
+ for (int i = 0; i < maxInstances; i++) {
+ testList.add(new Encode(mMime, mEncoderName, mIsAsync));
+ }
+ List<Future<Double>> resultList = pool.invokeAll(testList);
+ double achievedFrameRate = 0.0;
+ for (Future<Double> result : resultList) {
+ achievedFrameRate += result.get();
+ }
+ // Achieved frame rate is not compared as this test runs in byte buffer mode.
+ }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPairPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPairPerfTest.java
new file mode 100644
index 0000000..a5585d0
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPairPerfTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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 android.util.Pair;
+import android.view.Surface;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import static org.junit.Assert.assertTrue;
+
+@RunWith(Parameterized.class)
+public class MultiTranscoderPairPerfTest extends MultiCodecPerfTestBase {
+ private static final String LOG_TAG = MultiTranscoderPairPerfTest.class.getSimpleName();
+
+ private final Pair<String, String> mDecoderPair;
+ private final Pair<String, String> mEncoderPair;
+
+ @Rule
+ public ActivityTestRule<TestActivity> mActivityRule =
+ new ActivityTestRule<>(TestActivity.class);
+
+
+ public MultiTranscoderPairPerfTest(Pair<String, String> decoderPair,
+ Pair<String, String> encoderPair, boolean isAsync) {
+ super(null, null, isAsync);
+ mDecoderPair = decoderPair;
+ mEncoderPair = encoderPair;
+ }
+
+ @Parameterized.Parameters(name = "{index}({0}_{1}_{2})")
+ public static Collection<Object[]> inputParams() {
+ // Prepares the params list with the supported Hardware decoders/encoders in the device
+ final List<Object[]> argsList = new ArrayList<>();
+ ArrayList<Pair<String, String>> mimeTypeDecoderPairs = new ArrayList<>();
+ ArrayList<Pair<String, String>> mimeTypeEncoderPairs = new ArrayList<>();
+ for (String mime : mMimeList) {
+ ArrayList<String> listOfDecoders = getHardwareCodecsFor720p(mime, false);
+ for (String decoder : listOfDecoders) {
+ mimeTypeDecoderPairs.add(Pair.create(mime, decoder));
+ }
+ ArrayList<String> listOfEncoders = getHardwareCodecsFor720p(mime, true);
+ for (String encoder : listOfEncoders) {
+ mimeTypeEncoderPairs.add(Pair.create(mime, encoder));
+ }
+ }
+ for (Pair<String, String> mimeTypeDecoderPair : mimeTypeDecoderPairs) {
+ for (Pair<String, String> mimeTypeEncoderPair : mimeTypeEncoderPairs) {
+ for (boolean isAsync : boolStates) {
+ argsList.add(new Object[]{mimeTypeDecoderPair, mimeTypeEncoderPair, isAsync});
+ }
+ }
+ }
+ return argsList;
+ }
+
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ public void test720p() throws Exception {
+ ArrayList<Pair<String, String>> mimeCodecPairs = new ArrayList<>();
+ mimeCodecPairs.add(mDecoderPair);
+ mimeCodecPairs.add(mEncoderPair);
+ int maxInstances = checkAndGetMaxSupportedInstancesFor720p(mimeCodecPairs);
+ ExecutorService pool = Executors.newFixedThreadPool(maxInstances / 2 + maxInstances % 2);
+ List<Transcode> transcodeList = new ArrayList<>();
+ for (int i = 0; i < maxInstances / 2 ; i++) {
+ transcodeList.add(new Transcode(mEncoderPair.first, mTestFiles.get(mDecoderPair.first),
+ mDecoderPair.second, mEncoderPair.second, mIsAsync));
+ }
+ double achievedFrameRate = 0.0;
+ if (maxInstances % 2 == 1) {
+ List<DecodeToSurface> decodeList = new ArrayList<>();
+ mActivityRule.getActivity().waitTillSurfaceIsCreated();
+ Surface surface = mActivityRule.getActivity().getSurface();
+ assertTrue("Surface created is null.", surface != null);
+ assertTrue("Surface created is invalid.", surface.isValid());
+ mActivityRule.getActivity().setScreenParams(1280, 720, true);
+ decodeList.add(new DecodeToSurface(mDecoderPair.first,
+ mTestFiles.get(mDecoderPair.first), mDecoderPair.second, surface, mIsAsync));
+ List<Future<Double>> decodeResultList = pool.invokeAll(decodeList);
+ for (Future<Double> result : decodeResultList) {
+ achievedFrameRate += result.get();
+ }
+ }
+ List<Future<Double>> transcodeResultList = pool.invokeAll(transcodeList);
+ for (Future<Double> result : transcodeResultList) {
+ achievedFrameRate += result.get();
+ }
+ assertTrue("Unable to achieve the maxFrameRate supported. act/exp: " + achievedFrameRate
+ + "/" + mMaxFrameRate / 2, achievedFrameRate >= mMaxFrameRate / 2);
+ }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java b/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java
new file mode 100644
index 0000000..b63e22d
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/MultiTranscoderPerfTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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 android.util.Pair;
+
+import androidx.test.filters.LargeTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import static org.junit.Assert.assertTrue;
+
+@RunWith(Parameterized.class)
+public class MultiTranscoderPerfTest extends MultiCodecPerfTestBase {
+ private static final String LOG_TAG = MultiTranscoderPerfTest.class.getSimpleName();
+
+ private final String mDecoderName;
+ private final String mEncoderName;
+
+ public MultiTranscoderPerfTest(String mimeType, String testFile, String decoderName,
+ String encoderName, boolean isAsync) {
+ super(mimeType, testFile,isAsync);
+ mDecoderName = decoderName;
+ mEncoderName = encoderName;
+ }
+
+ @Parameterized.Parameters(name = "{index}({0}_{2}_{3}_{4})")
+ public static Collection<Object[]> inputParams() {
+ // Prepares the params list with the supported Hardware decoders/encoders in the device
+ final List<Object[]> argsList = new ArrayList<>();
+ for (String mime : mMimeList) {
+ ArrayList<String> listOfDecoders = getHardwareCodecsFor720p(mime, false);
+ ArrayList<String> listOfEncoders = getHardwareCodecsFor720p(mime, true);
+ for (String decoder : listOfDecoders) {
+ for (String encoder : listOfEncoders) {
+ for (boolean isAsync : boolStates) {
+ argsList.add(new Object[]{mime, mTestFiles.get(mime), decoder, encoder,
+ isAsync});
+ }
+ }
+ }
+ }
+ return argsList;
+ }
+
+ @LargeTest
+ @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ public void test720p() throws Exception {
+ ArrayList<Pair<String, String>> mimeCodecPairs = new ArrayList<>();
+ mimeCodecPairs.add(Pair.create(mMime, mDecoderName));
+ mimeCodecPairs.add(Pair.create(mMime, mEncoderName));
+ int maxInstances = checkAndGetMaxSupportedInstancesFor720p(mimeCodecPairs);
+ assertTrue("Decoder " + mDecoderName + " ,Encoder " + mEncoderName +
+ " unable to support minimum concurrent instances. act/exp: " + maxInstances + "/" +
+ (REQUIRED_MIN_CONCURRENT_INSTANCES / 2),
+ maxInstances >= (REQUIRED_MIN_CONCURRENT_INSTANCES / 2));
+ ExecutorService pool = Executors.newFixedThreadPool(maxInstances / 2);
+ List<Transcode> testList = new ArrayList<>();
+ for (int i = 0; i < maxInstances / 2; i++) {
+ testList.add(new Transcode(mMime, mTestFile, mDecoderName, mEncoderName, mIsAsync));
+ }
+ List<Future<Double>> resultList = pool.invokeAll(testList);
+ double achievedFrameRate = 0.0;
+ for (Future<Double> result : resultList) {
+ achievedFrameRate += result.get();
+ }
+ assertTrue("Unable to achieve the maxFrameRate supported. act/exp: " + achievedFrameRate
+ + "/" + mMaxFrameRate / 2, achievedFrameRate >= mMaxFrameRate / 2);
+ }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java b/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
new file mode 100644
index 0000000..8e440b4
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/PerformanceClassTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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 android.content.pm.PackageManager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests the basic aspects of the media performance class.
+ */
+public class PerformanceClassTest {
+ private boolean isHandheld() {
+ // handheld nature is not exposed to package manager, for now
+ // we check for touchscreen and NOT watch and NOT tv
+ PackageManager pm =
+ InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
+ return pm.hasSystemFeature(pm.FEATURE_TOUCHSCREEN)
+ && !pm.hasSystemFeature(pm.FEATURE_WATCH)
+ && !pm.hasSystemFeature(pm.FEATURE_TELEVISION)
+ && !pm.hasSystemFeature(pm.FEATURE_AUTOMOTIVE);
+ }
+
+ @SmallTest
+ @Test
+ public void testMediaPerformanceClassScope() throws Exception {
+ // if device is not of a performance class, we are done.
+ Assume.assumeTrue("not a device of a valid media performance class", Utils.isPerfClass());
+
+ if (Utils.isRPerfClass()
+ || Utils.isSPerfClass()) {
+ assertTrue("performance class is only defined for Handheld devices",
+ isHandheld());
+ }
+ }
+}
+
diff --git a/tests/mediapc/src/android/mediapc/cts/TestActivity.java b/tests/mediapc/src/android/mediapc/cts/TestActivity.java
new file mode 100644
index 0000000..bd93df0
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/TestActivity.java
@@ -0,0 +1,109 @@
+/*
+ * 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 android.app.Activity;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.ViewGroup;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class TestActivity extends Activity implements SurfaceHolder.Callback {
+ private static final String LOG_TAG = TestActivity.class.getSimpleName();
+ private SurfaceView mSurfaceView;
+ private SurfaceHolder mHolder;
+ private Surface mSurface;
+ private final Lock mLock = new ReentrantLock();
+ private final Condition mCondition = mLock.newCondition();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.media_decoder_surface_layout);
+ mSurfaceView = findViewById(R.id.surface);
+ mHolder = mSurfaceView.getHolder();
+ mHolder.addCallback(this);
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ Log.v(LOG_TAG, "surface created");
+ mLock.lock();
+ mSurface = mHolder.getSurface();
+ mLock.unlock();
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ Log.v(LOG_TAG, "surface changed " + format + " " + width + " " + height);
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ Log.v(LOG_TAG, "surface deleted");
+ mLock.lock();
+ mSurface = null;
+ mLock.unlock();
+ }
+
+ public void waitTillSurfaceIsCreated() throws InterruptedException {
+ final long mWaitTimeMs = 1000;
+ final int retries = 3;
+ mLock.lock();
+ final long start = SystemClock.elapsedRealtime();
+ while ((SystemClock.elapsedRealtime() - start) < (retries * mWaitTimeMs) &&
+ mSurface == null) {
+ mCondition.await(mWaitTimeMs, TimeUnit.MILLISECONDS);
+ }
+ mLock.unlock();
+ if (mSurface == null) {
+ throw new InterruptedException("Taking too long to attach a SurfaceView to a window.");
+ }
+ }
+
+ public Surface getSurface() {
+ return mSurface;
+ }
+
+ public void setScreenParams(int width, int height, boolean noStretch) {
+ ViewGroup.LayoutParams lp = mSurfaceView.getLayoutParams();
+ final DisplayMetrics dm = getResources().getDisplayMetrics();
+ if (noStretch && width <= dm.widthPixels && height <= dm.heightPixels) {
+ lp.width = width;
+ lp.height = height;
+ } else {
+ int a = dm.widthPixels * height / width;
+ if (a <= dm.heightPixels) {
+ lp.width = dm.widthPixels;
+ lp.height = a;
+ } else {
+ lp.width = dm.heightPixels * width / height;
+ lp.height = dm.heightPixels;
+ }
+ }
+ runOnUiThread(() -> mSurfaceView.setLayoutParams(lp));
+ }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/Utils.java b/tests/mediapc/src/android/mediapc/cts/Utils.java
new file mode 100644
index 0000000..2912f5d
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/Utils.java
@@ -0,0 +1,63 @@
+/*
+ * 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 android.os.Build;
+import android.os.SystemProperties;
+import android.util.Log;
+
+/**
+ * Test utilities.
+ */
+/* package private */ class Utils {
+ private static final int sPc = SystemProperties.getInt(
+ "ro.odm.build.media_performance_class", 0);
+
+ private static final String TAG = "PerformanceClassTestUtils";
+
+ static {
+ Log.d(TAG, "performance class is " + sPc);
+ }
+
+ /**
+ * First defined media performance class.
+ */
+ private static final int FIRST_PERFORMANCE_CLASS = Build.VERSION_CODES.R;
+
+ public static boolean isRPerfClass() {
+ return sPc == Build.VERSION_CODES.R;
+ }
+
+ public static boolean isSPerfClass() {
+ return sPc == Build.VERSION_CODES.R + 1; /* TODO: make this S */
+ }
+
+ /**
+ * Latest defined media performance class.
+ */
+ /* TODO: make this S */
+ private static final int LAST_PERFORMANCE_CLASS = Build.VERSION_CODES.R + 1;
+
+ public static int getPerfClass() {
+ return sPc;
+ }
+
+ public static boolean isPerfClass() {
+ return sPc >= FIRST_PERFORMANCE_CLASS &&
+ sPc <= LAST_PERFORMANCE_CLASS;
+ }
+}
diff --git a/tests/mediapc/src/android/mediapc/cts/WorkDir.java b/tests/mediapc/src/android/mediapc/cts/WorkDir.java
new file mode 100644
index 0000000..7f93f43
--- /dev/null
+++ b/tests/mediapc/src/android/mediapc/cts/WorkDir.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.mediapc.cts;
+
+import android.os.Environment;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Assert;
+
+import java.io.File;
+
+class WorkDir {
+ private static final String MEDIA_PATH_INSTR_ARG_KEY = "media-path";
+ static private final File getTopDir() {
+ Assert.assertEquals(Environment.getExternalStorageState(), Environment.MEDIA_MOUNTED);
+ return Environment.getExternalStorageDirectory();
+ }
+ static private final String getTopDirString() {
+ return (getTopDir().getAbsolutePath() + File.separator);
+ }
+ static final String getMediaDirString() {
+ android.os.Bundle bundle = InstrumentationRegistry.getArguments();
+ String mediaDirString = bundle.getString(MEDIA_PATH_INSTR_ARG_KEY);
+ if (mediaDirString != null) {
+ // user has specified the mediaDirString via instrumentation-arg
+ return mediaDirString + ((mediaDirString.endsWith("/")) ? "" : "/");
+ } else {
+ return (getTopDirString() + "test/CtsMediaPerformanceClassTestCases-1.0/");
+ }
+ }
+}
diff --git a/tests/netlegacy22.api/Android.bp b/tests/netlegacy22.api/Android.bp
new file mode 100644
index 0000000..b28f8a0
--- /dev/null
+++ b/tests/netlegacy22.api/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsNetTestCasesLegacyApi22",
+ defaults: ["cts_defaults"],
+ srcs: ["src/**/*.java"],
+ platform_apis: true,
+ static_libs: [
+ "ctstestrunner-axt",
+ "compatibility-device-util-axt",
+ ],
+ libs: ["android.test.base"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+}
diff --git a/tests/netlegacy22.api/Android.mk b/tests/netlegacy22.api/Android.mk
deleted file mode 100644
index 53c910d..0000000
--- a/tests/netlegacy22.api/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsNetTestCasesLegacyApi22
-
-LOCAL_SDK_VERSION := 22
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner-axt compatibility-device-util-axt
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/netlegacy22.api/AndroidManifest.xml b/tests/netlegacy22.api/AndroidManifest.xml
index a9411cc..e062e14 100644
--- a/tests/netlegacy22.api/AndroidManifest.xml
+++ b/tests/netlegacy22.api/AndroidManifest.xml
@@ -18,6 +18,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.netlegacy22.api.cts">
+ <uses-sdk android:targetSdkVersion="22" />
+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
diff --git a/tests/netlegacy22.api/OWNERS b/tests/netlegacy22.api/OWNERS
index 3fcbaf3..9b1555e 100644
--- a/tests/netlegacy22.api/OWNERS
+++ b/tests/netlegacy22.api/OWNERS
@@ -1,2 +1,3 @@
# Bug component: 31808
-include ../tests/net/OWNERS
+set noparent
+include platform/packages/modules/Connectivity:/tests/cts/OWNERS
diff --git a/tests/netlegacy22.api/TEST_MAPPING b/tests/netlegacy22.api/TEST_MAPPING
new file mode 100644
index 0000000..38a8470
--- /dev/null
+++ b/tests/netlegacy22.api/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "postsubmit": [
+ {
+ "name": "CtsNetTestCasesLegacyApi22"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/netlegacy22.api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java b/tests/netlegacy22.api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
index 4a8a2ad..b7880c7 100644
--- a/tests/netlegacy22.api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
+++ b/tests/netlegacy22.api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
@@ -50,6 +50,7 @@
private static final String HOST_ADDRESS1 = "192.0.2.1";
private static final String HOST_ADDRESS2 = "192.0.2.2";
private static final String HOST_ADDRESS3 = "192.0.2.3";
+ private static final String HOST_ADDRESS4 = "192.0.2.4";
// These are correct as of API level 22, which is what we target here.
private static final int APN_REQUEST_FAILED = 3;
@@ -163,8 +164,13 @@
assertTrue("Couldn't requestRouteToHost using HIPRI.",
mCm.requestRouteToHost(TYPE_MOBILE_HIPRI, ipv4AddrToInt(HOST_ADDRESS1)));
+ assertTrue("Couldn't requestRouteToHostAddress using HIPRI.",
+ mCm.requestRouteToHostAddress(TYPE_MOBILE_HIPRI,
+ InetAddress.getByName(HOST_ADDRESS3)));
+
checkSourceAddress(HOST_ADDRESS1, TYPE_MOBILE);
checkSourceAddress(HOST_ADDRESS2, TYPE_WIFI);
+ checkSourceAddress(HOST_ADDRESS3, TYPE_MOBILE);
// TODO check dns selection
@@ -282,7 +288,7 @@
try {
assertTrue("Network type " + type,
- mCm.requestRouteToHost(type, ipv4AddrToInt(HOST_ADDRESS3)) == expectToWork);
+ mCm.requestRouteToHost(type, ipv4AddrToInt(HOST_ADDRESS4)) == expectToWork);
} catch (Exception e) {
Log.d(TAG, "got exception in requestRouteToHost for type " + type);
assertFalse("Exception received for type " + type, expectToWork);
@@ -291,6 +297,6 @@
//TODO verify route table
}
- assertFalse(mCm.requestRouteToHost(-1, ipv4AddrToInt(HOST_ADDRESS1)));
+ assertFalse(mCm.requestRouteToHost(-1, ipv4AddrToInt(HOST_ADDRESS4)));
}
}
diff --git a/tests/openglperf2/Android.bp b/tests/openglperf2/Android.bp
new file mode 100644
index 0000000..ce83be2
--- /dev/null
+++ b/tests/openglperf2/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsOpenGlPerf2TestCases",
+ defaults: ["cts_defaults"],
+ srcs: ["src/**/*.java"],
+ // Include both the 32 and 64 bit versions
+ compile_multilib: "both",
+ static_libs: [
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ ],
+ jni_libs: ["libctsopengl_jni"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+ //LOCAL_MIN_SDK_VERSION := 16
+ sdk_version: "16",
+}
diff --git a/tests/openglperf2/Android.mk b/tests/openglperf2/Android.mk
deleted file mode 100644
index a6de6c8..0000000
--- a/tests/openglperf2/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-# Include both the 32 and 64 bit versions
-LOCAL_MULTILIB := both
-
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util-axt ctstestrunner-axt
-
-LOCAL_JNI_SHARED_LIBRARIES := libctsopengl_jni
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsOpenGlPerf2TestCases
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-
-LOCAL_SDK_VERSION := 16
-#LOCAL_MIN_SDK_VERSION := 16
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/security/src/android/keystore/cts/Attestation.java b/tests/security/src/android/keystore/cts/Attestation.java
index e9ff0d2..ae2e29a 100644
--- a/tests/security/src/android/keystore/cts/Attestation.java
+++ b/tests/security/src/android/keystore/cts/Attestation.java
@@ -39,6 +39,16 @@
public static final int KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT = 1;
public static final int KM_SECURITY_LEVEL_STRONG_BOX = 2;
+ // Known KeyMaster/KeyMint versions. This is the version number
+ // which appear in the keymasterVersion field.
+ public static final int KM_VERSION_KEYMASTER_1 = 10;
+ public static final int KM_VERSION_KEYMASTER_1_1 = 11;
+ public static final int KM_VERSION_KEYMASTER_2 = 20;
+ public static final int KM_VERSION_KEYMASTER_3 = 30;
+ public static final int KM_VERSION_KEYMASTER_4 = 40;
+ public static final int KM_VERSION_KEYMASTER_4_1 = 41;
+ public static final int KM_VERSION_KEYMINT_1 = 100;
+
int attestationVersion;
int keymasterVersion;
int keymasterSecurityLevel;
@@ -107,6 +117,7 @@
public abstract RootOfTrust getRootOfTrust();
+ // Returns one of the KM_VERSION_* values define above.
public int getKeymasterVersion() {
return keymasterVersion;
}
diff --git a/tests/signature/api-check/Android.bp b/tests/signature/api-check/Android.bp
index 3f686c2..5e7ff3b 100644
--- a/tests/signature/api-check/Android.bp
+++ b/tests/signature/api-check/Android.bp
@@ -70,12 +70,6 @@
static_libs: ["cts-api-signature-test"],
}
-// Access the hiddenapi-flags.csv file produced by the build.
-hiddenapi_flags {
- name: "cts-hiddenapi-flags-csv",
- filename: "hiddenapi-flags.csv",
-}
-
filegroup {
name: "cts-api-hiddenapi-filter-csv",
srcs: [
@@ -88,7 +82,7 @@
name: "hiddenapi-blocklist-check-defaults",
defaults: ["signature-api-check-defaults"],
java_resources: [
- ":cts-hiddenapi-flags-csv",
+ ":platform-bootclasspath{hiddenapi-flags.csv}",
":cts-api-hiddenapi-filter-csv"
],
jni_libs: [
diff --git a/tests/signature/api-check/shared-libs-api/Android.mk b/tests/signature/api-check/shared-libs-api/Android.mk
index 3128444..852c9db 100644
--- a/tests/signature/api-check/shared-libs-api/Android.mk
+++ b/tests/signature/api-check/shared-libs-api/Android.mk
@@ -71,6 +71,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := cts-api-signature-multilib-test
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
include $(LOCAL_PATH)/../build_signature_apk.mk
LOCAL_JAVA_SDK_LIBRARIES :=
diff --git a/tests/signature/api-check/shared-libs-api/src/android/signature/cts/api/SignatureMultiLibsTest.java b/tests/signature/api-check/shared-libs-api/src/android/signature/cts/api/SignatureMultiLibsTest.java
index f74a027..4c0a31a 100644
--- a/tests/signature/api-check/shared-libs-api/src/android/signature/cts/api/SignatureMultiLibsTest.java
+++ b/tests/signature/api-check/shared-libs-api/src/android/signature/cts/api/SignatureMultiLibsTest.java
@@ -42,7 +42,7 @@
runWithTestResultObserver(mResultObserver -> {
ApiComplianceChecker complianceChecker =
- new ApiComplianceChecker(mResultObserver, classProvider);
+ new ApiComplianceChecker(mResultObserver, mClassProvider);
ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/AbstractApiTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/AbstractApiTest.java
index 1e96910..9707dd8 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/AbstractApiTest.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/AbstractApiTest.java
@@ -26,17 +26,13 @@
import android.signature.cts.VirtualPath.LocalFilePath;
import android.signature.cts.VirtualPath.ResourcePath;
import android.util.Log;
-import java.io.File;
+
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
-import java.util.EnumSet;
import java.util.stream.Stream;
import java.util.zip.ZipFile;
import repackaged.android.test.InstrumentationTestCase;
@@ -50,7 +46,7 @@
private TestResultObserver mResultObserver;
- ClassProvider classProvider;
+ ClassProvider mClassProvider;
protected String getGlobalExemptions() {
return Settings.Global.getString(
@@ -90,7 +86,7 @@
// out known inaccessible classes.
// Note that com.android.internal.R.* inner classes are also excluded as they are
// not part of API though exist in the runtime.
- classProvider = new ExcludingClassProvider(
+ mClassProvider = new ExcludingClassProvider(
new BootClassPathClassesProvider(),
name -> name != null && name.startsWith("com.android.internal.R."));
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/BaseKillswitchTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/BaseKillswitchTest.java
index 2337ced..10907d0 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/BaseKillswitchTest.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/BaseKillswitchTest.java
@@ -18,8 +18,6 @@
import java.util.function.Predicate;
-import android.os.Bundle;
-import android.provider.Settings;
import android.signature.cts.DexField;
import android.signature.cts.DexMember;
import android.signature.cts.DexMemberChecker;
@@ -127,8 +125,8 @@
}
};
- classProvider.getAllClasses().forEach(klass -> {
- classProvider.getAllMembers(klass)
+ mClassProvider.getAllClasses().forEach(klass -> {
+ mClassProvider.getAllMembers(klass)
.filter(memberFilter)
.forEach(member -> {
DexMemberChecker.checkSingleMember(member, reflection, jni, observer);
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/SignatureTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/SignatureTest.java
index 440430d..2ef70ca 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/SignatureTest.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/SignatureTest.java
@@ -58,7 +58,7 @@
runWithTestResultObserver(mResultObserver -> {
Set<JDiffClassDescription> unexpectedClasses = loadUnexpectedClasses();
for (JDiffClassDescription classDescription : unexpectedClasses) {
- Class<?> unexpectedClass = findUnexpectedClass(classDescription, classProvider);
+ Class<?> unexpectedClass = findUnexpectedClass(classDescription, mClassProvider);
if (unexpectedClass != null) {
mResultObserver.notifyFailure(
FailureType.UNEXPECTED_CLASS,
@@ -68,7 +68,7 @@
}
ApiComplianceChecker complianceChecker =
- new ApiComplianceChecker(mResultObserver, classProvider);
+ new ApiComplianceChecker(mResultObserver, mClassProvider);
// Load classes from any API files that form the base which the expected APIs extend.
loadBaseClasses(complianceChecker);
diff --git a/tests/signature/api-check/system-annotation/src/java/android/signature/cts/api/AnnotationTest.java b/tests/signature/api-check/system-annotation/src/java/android/signature/cts/api/AnnotationTest.java
index efefdd5..a3c46d5 100644
--- a/tests/signature/api-check/system-annotation/src/java/android/signature/cts/api/AnnotationTest.java
+++ b/tests/signature/api-check/system-annotation/src/java/android/signature/cts/api/AnnotationTest.java
@@ -27,6 +27,7 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.util.function.Predicate;
/**
* Checks that parts of the device's API that are annotated (e.g. with android.annotation.SystemApi)
@@ -36,13 +37,22 @@
private static final String TAG = AnnotationTest.class.getSimpleName();
- private String[] expectedApiFiles;
- private String annotationForExactMatch;
+ private String[] mExpectedApiFiles;
+ private String mAnnotationForExactMatch;
@Override
protected void initializeFromArgs(Bundle instrumentationArgs) throws Exception {
- expectedApiFiles = getCommaSeparatedList(instrumentationArgs, "expected-api-files");
- annotationForExactMatch = instrumentationArgs.getString("annotation-for-exact-match");
+ mExpectedApiFiles = getCommaSeparatedList(instrumentationArgs, "expected-api-files");
+ mAnnotationForExactMatch = instrumentationArgs.getString("annotation-for-exact-match");
+ }
+
+ private Predicate<? super JDiffClassDescription> androidAutoClassesFilter() {
+ if (getInstrumentation().getContext().getPackageManager().hasSystemFeature(
+ "android.hardware.type.automotive")) {
+ return clz -> true;
+ } else {
+ return clz -> !clz.getAbsoluteClassName().startsWith("android.car.");
+ }
}
/**
@@ -50,44 +60,42 @@
* android.annotation.SystemApi) match the API definition.
*/
public void testAnnotation() {
- if ("true".equals(PropertyUtil.getProperty("ro.treble.enabled")) &&
- PropertyUtil.getFirstApiLevel() > Build.VERSION_CODES.O_MR1) {
- AnnotationChecker.ResultFilter filter = new AnnotationChecker.ResultFilter() {
- @Override
- public boolean skip(Class<?> clazz) {
- return false;
- }
+ AnnotationChecker.ResultFilter filter = new AnnotationChecker.ResultFilter() {
+ @Override
+ public boolean skip(Class<?> clazz) {
+ return false;
+ }
- @Override
- public boolean skip(Constructor<?> ctor) {
- return false;
- }
+ @Override
+ public boolean skip(Constructor<?> ctor) {
+ return false;
+ }
- @Override
- public boolean skip(Method m) {
- return false;
- }
+ @Override
+ public boolean skip(Method m) {
+ return false;
+ }
- @Override
- public boolean skip(Field f) {
- // The R.styleable class is not part of the API because it's annotated with
- // @doconly. But the class actually exists in the runtime classpath. To avoid
- // the mismatch, skip the check for fields from the class.
- return "android.R$styleable".equals(f.getDeclaringClass().getName());
- }
- };
- runWithTestResultObserver(resultObserver -> {
- AnnotationChecker complianceChecker = new AnnotationChecker(resultObserver,
- classProvider, annotationForExactMatch, filter);
+ @Override
+ public boolean skip(Field f) {
+ // The R.styleable class is not part of the API because it's annotated with
+ // @doconly. But the class actually exists in the runtime classpath. To avoid
+ // the mismatch, skip the check for fields from the class.
+ return "android.R$styleable".equals(f.getDeclaringClass().getName());
+ }
+ };
+ runWithTestResultObserver(resultObserver -> {
+ AnnotationChecker complianceChecker = new AnnotationChecker(resultObserver,
+ mClassProvider, mAnnotationForExactMatch, filter);
- ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
+ ApiDocumentParser apiDocumentParser = new ApiDocumentParser(TAG);
- parseApiResourcesAsStream(apiDocumentParser, expectedApiFiles)
- .forEach(complianceChecker::checkSignatureCompliance);
+ parseApiResourcesAsStream(apiDocumentParser, mExpectedApiFiles)
+ .filter(androidAutoClassesFilter())
+ .forEach(complianceChecker::checkSignatureCompliance);
- // After done parsing all expected API files, perform any deferred checks.
- complianceChecker.checkDeferred();
- });
- }
+ // After done parsing all expected API files, perform any deferred checks.
+ complianceChecker.checkDeferred();
+ });
}
}
diff --git a/tests/signature/api-check/system-api/Android.mk b/tests/signature/api-check/system-api/Android.mk
index 6649ed8..ccb3c58 100644
--- a/tests/signature/api-check/system-api/Android.mk
+++ b/tests/signature/api-check/system-api/Android.mk
@@ -55,6 +55,8 @@
system-current.api.gz \
system-removed.api.gz \
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
include $(LOCAL_PATH)/../build_signature_apk.mk
all_system_api_files :=
diff --git a/tests/signature/intent-check/DynamicConfig.xml b/tests/signature/intent-check/DynamicConfig.xml
index 4dc7b8a..7c33d1a 100644
--- a/tests/signature/intent-check/DynamicConfig.xml
+++ b/tests/signature/intent-check/DynamicConfig.xml
@@ -25,6 +25,8 @@
Bug: 78574873 android.intent.action.EPHEMERAL_RESOLVER_SETTINGS
Bug: 150153196 android.intent.action.LOAD_DATA (system in API 30)
Bug: 150153196 android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY (system in API 30)
+ Bug: 187483828 android.intent.action.VIEW_PERMISSION_USAGE_FOR_PERIOD
+ Bug: 187483828 android.intent.action.ACTIVITY_RECOGNIZER
-->
<dynamicConfig>
<entry key ="intent_whitelist">
@@ -38,5 +40,7 @@
<value>android.intent.action.EPHEMERAL_RESOLVER_SETTINGS</value>
<value>android.intent.action.LOAD_DATA</value>
<value>android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY</value>
+ <value>android.intent.action.VIEW_PERMISSION_USAGE_FOR_PERIOD</value>
+ <value>android.intent.action.ACTIVITY_RECOGNIZER</value>
</entry>
</dynamicConfig>
diff --git a/tests/signature/lib/common/src/android/signature/cts/AnnotationChecker.java b/tests/signature/lib/common/src/android/signature/cts/AnnotationChecker.java
index 3f14dad..1567f16 100644
--- a/tests/signature/lib/common/src/android/signature/cts/AnnotationChecker.java
+++ b/tests/signature/lib/common/src/android/signature/cts/AnnotationChecker.java
@@ -27,7 +27,7 @@
/**
* Checks that the runtime representation of a class matches the API representation of a class.
*/
-public class AnnotationChecker extends AbstractApiChecker {
+public class AnnotationChecker extends ApiPresenceChecker {
private final String annotationSpec;
@@ -39,7 +39,7 @@
private final Map<String, Set<Field>> annotatedFieldsMap = new HashMap<>();
/**
- * @param annotationName name of the annotation class for the API type (e.g.
+ * @param annotationSpec name of the annotation class for the API type (e.g.
* android.annotation.SystemApi)
*/
public AnnotationChecker(
@@ -82,7 +82,6 @@
public boolean skip(Field f);
}
- @Override
public void checkDeferred() {
for (Class<?> clazz : annotatedClassesMap.values()) {
if (filter != null && filter.skip(clazz)) continue;
@@ -117,17 +116,6 @@
}
@Override
- protected boolean allowMissingClass(JDiffClassDescription classDescription) {
- // A class that exist in the API document is not found in the runtime.
- // This can happen for classes that are optional (e.g. classes for
- // Android Auto). This, however, should not be considered as a test
- // failure, because the purpose of this test is to ensure that every
- // runtime classes found in the device have more annotations than
- // the documented.
- return true;
- }
-
- @Override
protected boolean checkClass(JDiffClassDescription classDescription, Class<?> runtimeClass) {
// remove the class from the set if found
annotatedClassesMap.remove(runtimeClass.getName());
diff --git a/tests/signature/lib/common/src/android/signature/cts/ApiComplianceChecker.java b/tests/signature/lib/common/src/android/signature/cts/ApiComplianceChecker.java
index f1c812e..fe67157 100644
--- a/tests/signature/lib/common/src/android/signature/cts/ApiComplianceChecker.java
+++ b/tests/signature/lib/common/src/android/signature/cts/ApiComplianceChecker.java
@@ -29,7 +29,7 @@
/**
* Checks that the runtime representation of a class matches the API representation of a class.
*/
-public class ApiComplianceChecker extends AbstractApiChecker {
+public class ApiComplianceChecker extends ApiPresenceChecker {
/**
* A set of method signatures whose abstract modifier should be ignored.
@@ -73,7 +73,6 @@
interfaceChecker = new InterfaceChecker(resultObserver, classProvider);
}
- @Override
public void checkDeferred() {
interfaceChecker.checkQueued();
}
diff --git a/tests/signature/lib/common/src/android/signature/cts/AbstractApiChecker.java b/tests/signature/lib/common/src/android/signature/cts/ApiPresenceChecker.java
similarity index 86%
rename from tests/signature/lib/common/src/android/signature/cts/AbstractApiChecker.java
rename to tests/signature/lib/common/src/android/signature/cts/ApiPresenceChecker.java
index 03c4a85..fc4335c 100644
--- a/tests/signature/lib/common/src/android/signature/cts/AbstractApiChecker.java
+++ b/tests/signature/lib/common/src/android/signature/cts/ApiPresenceChecker.java
@@ -27,13 +27,13 @@
* Base class for those that process a set of API definition files and perform some checking on
* them.
*/
-public abstract class AbstractApiChecker {
+public class ApiPresenceChecker {
final ResultObserver resultObserver;
final ClassProvider classProvider;
- AbstractApiChecker(ClassProvider classProvider, ResultObserver resultObserver) {
+ public ApiPresenceChecker(ClassProvider classProvider, ResultObserver resultObserver) {
this.classProvider = classProvider;
this.resultObserver = resultObserver;
}
@@ -63,14 +63,10 @@
.findRequiredClass(classDescription, classProvider);
if (runtimeClass == null) {
- // No class found, notify the observer according to the class type,
- // if missing a class isn't acceptable.
- if (!allowMissingClass(classDescription)) {
- resultObserver.notifyFailure(FailureType.missing(classDescription),
- classDescription.getAbsoluteClassName(),
- "Classloader is unable to find " + classDescription
- .getAbsoluteClassName());
- }
+ resultObserver.notifyFailure(FailureType.missing(classDescription),
+ classDescription.getAbsoluteClassName(),
+ "Classloader is unable to find " + classDescription
+ .getAbsoluteClassName());
return null;
}
@@ -90,11 +86,6 @@
}
/**
- * Perform any additional checks that can only be done after all api files have been processed.
- */
- public abstract void checkDeferred();
-
- /**
* Implement to provide custom check of the supplied class description.
*
* <p>This should not peform checks on the members, those will be done separately depending
@@ -104,21 +95,12 @@
* @param runtimeClass the runtime class corresponding to the class description.
* @return true if the checks passed and the members should now be checked.
*/
- protected abstract boolean checkClass(JDiffClassDescription classDescription,
- Class<?> runtimeClass);
-
-
- /**
- * Checks that a class that exists in the API xml file but that does not exist
- * in the runtime is allowed or not.
- *
- * @param classDescription the class description that is missing.
- * @return true if missing the class is acceptable.
- */
- protected boolean allowMissingClass(JDiffClassDescription classDescription) {
- return false;
+ protected boolean checkClass(JDiffClassDescription classDescription,
+ Class<?> runtimeClass) {
+ return true;
}
+
/**
* Checks all fields in test class for compliance with the API xml.
*
@@ -175,9 +157,10 @@
return fieldMap;
}
- protected abstract void checkField(JDiffClassDescription classDescription,
+ protected void checkField(JDiffClassDescription classDescription,
Class<?> runtimeClass,
- JDiffClassDescription.JDiffField fieldDescription, Field field);
+ JDiffClassDescription.JDiffField fieldDescription, Field field) {
+ }
/**
@@ -217,9 +200,10 @@
}
}
- protected abstract void checkConstructor(JDiffClassDescription classDescription,
+ protected void checkConstructor(JDiffClassDescription classDescription,
Class<?> runtimeClass,
- JDiffClassDescription.JDiffConstructor ctorDescription, Constructor<?> ctor);
+ JDiffClassDescription.JDiffConstructor ctorDescription, Constructor<?> ctor) {
+ }
/**
* Checks that the method found through reflection matches the
@@ -260,7 +244,8 @@
}
}
- protected abstract void checkMethod(JDiffClassDescription classDescription,
+ protected void checkMethod(JDiffClassDescription classDescription,
Class<?> runtimeClass,
- JDiffClassDescription.JDiffMethod methodDescription, Method method);
+ JDiffClassDescription.JDiffMethod methodDescription, Method method) {
+ }
}
diff --git a/tests/signature/tests/src/android/signature/cts/tests/AnnotationCheckerTest.java b/tests/signature/tests/src/android/signature/cts/tests/AnnotationCheckerTest.java
index a981be7..3e18522 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/AnnotationCheckerTest.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/AnnotationCheckerTest.java
@@ -21,8 +21,9 @@
import android.signature.cts.FailureType;
import android.signature.cts.JDiffClassDescription;
import android.signature.cts.ResultObserver;
-import android.signature.cts.tests.data.ApiAnnotation;
+
import java.lang.reflect.Modifier;
+import java.util.function.Consumer;
import org.junit.Test;
import org.junit.runners.JUnit4;
@@ -32,7 +33,7 @@
* Test class for {@link android.signature.cts.AnnotationChecker}.
*/
@RunWith(JUnit4.class)
-public class AnnotationCheckerTest extends AbstractApiCheckerTest<AnnotationChecker> {
+public class AnnotationCheckerTest extends ApiPresenceCheckerTest<AnnotationChecker> {
@Override
protected AnnotationChecker createChecker(ResultObserver resultObserver,
@@ -41,6 +42,18 @@
"@android.signature.cts.tests.data.ApiAnnotation()", null);
}
+ @Override
+ void runWithApiChecker(ResultObserver resultObserver, Consumer<AnnotationChecker> consumer,
+ String... excludedRuntimeClasses) {
+ super.runWithApiChecker(
+ resultObserver,
+ checker -> {
+ consumer.accept(checker);
+ checker.checkDeferred();
+ },
+ excludedRuntimeClasses);
+ }
+
private static void addConstructor(JDiffClassDescription clz, String... paramTypes) {
JDiffClassDescription.JDiffConstructor constructor = new JDiffClassDescription.JDiffConstructor(
clz.getShortClassName(), Modifier.PUBLIC);
diff --git a/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java b/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java
index 405f5b2..c4c87f5 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/ApiComplianceCheckerTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
+import android.signature.cts.AnnotationChecker;
import android.signature.cts.ApiComplianceChecker;
import android.signature.cts.ClassProvider;
import android.signature.cts.FailureType;
@@ -28,8 +29,8 @@
import android.signature.cts.tests.data.NormalClass;
import android.signature.cts.tests.data.NormalInterface;
import java.lang.reflect.Modifier;
+import java.util.function.Consumer;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runners.JUnit4;
import org.junit.runner.RunWith;
@@ -38,7 +39,7 @@
* Test class for JDiffClassDescription.
*/
@RunWith(JUnit4.class)
-public class ApiComplianceCheckerTest extends AbstractApiCheckerTest<ApiComplianceChecker> {
+public class ApiComplianceCheckerTest extends ApiPresenceCheckerTest<ApiComplianceChecker> {
@Override
protected ApiComplianceChecker createChecker(ResultObserver resultObserver,
@@ -46,6 +47,18 @@
return new ApiComplianceChecker(resultObserver, provider);
}
+ @Override
+ void runWithApiChecker(
+ ResultObserver resultObserver, Consumer<ApiComplianceChecker> consumer, String... excludedRuntimeClasses) {
+ super.runWithApiChecker(
+ resultObserver,
+ checker -> {
+ consumer.accept(checker);
+ checker.checkDeferred();
+ },
+ excludedRuntimeClasses);
+ }
+
@Test
public void testNormalClassCompliance() {
JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName());
diff --git a/tests/signature/tests/src/android/signature/cts/tests/AbstractApiCheckerTest.java b/tests/signature/tests/src/android/signature/cts/tests/ApiPresenceCheckerTest.java
similarity index 95%
rename from tests/signature/tests/src/android/signature/cts/tests/AbstractApiCheckerTest.java
rename to tests/signature/tests/src/android/signature/cts/tests/ApiPresenceCheckerTest.java
index 901b424..719be91 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/AbstractApiCheckerTest.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/ApiPresenceCheckerTest.java
@@ -15,7 +15,7 @@
*/
package android.signature.cts.tests;
-import android.signature.cts.AbstractApiChecker;
+import android.signature.cts.ApiPresenceChecker;
import android.signature.cts.ClassProvider;
import android.signature.cts.ExcludingClassProvider;
import android.signature.cts.FailureType;
@@ -28,9 +28,9 @@
import org.junit.Assert;
/**
- * Base class for tests of implementations of {@link AbstractApiChecker}.
+ * Base class for tests of implementations of {@link ApiPresenceChecker}.
*/
-public abstract class AbstractApiCheckerTest<T extends AbstractApiChecker> {
+public abstract class ApiPresenceCheckerTest<T extends ApiPresenceChecker> {
static final String VALUE = "VALUE";
@@ -79,7 +79,6 @@
ClassProvider provider = createClassProvider(excludedRuntimeClasses);
T checker = createChecker(resultObserver, provider);
consumer.accept(checker);
- checker.checkDeferred();
}
protected abstract T createChecker(ResultObserver resultObserver, ClassProvider provider);
diff --git a/tests/simplecpu/Android.bp b/tests/simplecpu/Android.bp
new file mode 100644
index 0000000..3400544
--- /dev/null
+++ b/tests/simplecpu/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsSimpleCpuTestCases",
+ defaults: ["cts_defaults"],
+ srcs: ["src/**/*.java"],
+ // Include both the 32 and 64 bit versions
+ compile_multilib: "both",
+ static_libs: [
+ "compatibility-device-util-axt",
+ "ctstestrunner-axt",
+ ],
+ jni_libs: ["libctscpu_jni"],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+ sdk_version: "16",
+}
diff --git a/tests/simplecpu/Android.mk b/tests/simplecpu/Android.mk
deleted file mode 100644
index 7d1db20..0000000
--- a/tests/simplecpu/Android.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (C) 2012 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-
-# Include both the 32 and 64 bit versions
-LOCAL_MULTILIB := both
-
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util-axt ctstestrunner-axt
-
-LOCAL_JNI_SHARED_LIBRARIES := libctscpu_jni
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsSimpleCpuTestCases
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-
-LOCAL_SDK_VERSION := 16
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/accounts/common/lint-baseline.xml b/tests/tests/accounts/common/lint-baseline.xml
new file mode 100644
index 0000000..6a95c6c
--- /dev/null
+++ b/tests/tests/accounts/common/lint-baseline.xml
@@ -0,0 +1,697 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 5 (current min is 1): `android.accounts.AccountManager#get`"
+ errorLine1=" AccountManager am = AccountManager.get(context);"
+ errorLine2=" ~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/AuthenticatorContentProvider.java"
+ line="81"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 5 (current min is 1): `android.accounts.AccountManager#getAuthenticatorTypes`"
+ errorLine1=" AuthenticatorDescription[] authenticators = am.getAuthenticatorTypes();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/AuthenticatorContentProvider.java"
+ line="82"
+ column="56"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.AuthenticatorDescription#packageName`"
+ errorLine1=" if (a.packageName.equals(context.getPackageName())) {"
+ errorLine2=" ~~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/AuthenticatorContentProvider.java"
+ line="88"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 5 (current min is 1): `new android.accounts.Account`"
+ errorLine1=" Account account = new Account(name, a.type);"
+ errorLine2=" ~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/AuthenticatorContentProvider.java"
+ line="90"
+ column="39"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.AuthenticatorDescription#type`"
+ errorLine1=" Account account = new Account(name, a.type);"
+ errorLine2=" ~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/AuthenticatorContentProvider.java"
+ line="90"
+ column="57"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 5 (current min is 1): `android.accounts.AccountManager#addAccountExplicitly`"
+ errorLine1=" am.addAccountExplicitly(account, Fixtures.PREFIX_PASSWORD + name, null);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/AuthenticatorContentProvider.java"
+ line="91"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 5 (current min is 1): `android.accounts.AccountManager#get`"
+ errorLine1=" AccountManager am = AccountManager.get(context);"
+ errorLine2=" ~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/AuthenticatorContentProvider.java"
+ line="99"
+ column="44"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 5 (current min is 1): `android.accounts.AccountManager#getAuthenticatorTypes`"
+ errorLine1=" AuthenticatorDescription[] authenticators = am.getAuthenticatorTypes();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/AuthenticatorContentProvider.java"
+ line="100"
+ column="56"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.AuthenticatorDescription#packageName`"
+ errorLine1=" if (a.packageName.equals(context.getPackageName())) {"
+ errorLine2=" ~~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/AuthenticatorContentProvider.java"
+ line="106"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 5 (current min is 1): `android.accounts.AccountManager#getAccountsByType`"
+ errorLine1=" Account[] accountsToRemove = am.getAccountsByType(a.type);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/AuthenticatorContentProvider.java"
+ line="107"
+ column="49"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.AuthenticatorDescription#type`"
+ errorLine1=" Account[] accountsToRemove = am.getAccountsByType(a.type);"
+ errorLine2=" ~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/AuthenticatorContentProvider.java"
+ line="107"
+ column="67"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 22 (current min is 1): `android.accounts.AccountManager#removeAccountExplicitly`"
+ errorLine1=" am.removeAccountExplicitly(account);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/AuthenticatorContentProvider.java"
+ line="109"
+ column="24"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Cast from `Account` to `Parcelable` requires API level 5 (current min is 1)"
+ errorLine1=" out.writeParcelable(account, flags);"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/tx/ConfirmCredentialsTx.java"
+ line="50"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 5 (current min is 1): `new android.accounts.Account`"
+ errorLine1=" public static final Account ACCOUNT_UNAFFILIATED_FIXTURE_SUCCESS = new Account("
+ errorLine2=" ~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/Fixtures.java"
+ line="53"
+ column="72"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 5 (current min is 1): `new android.accounts.Account`"
+ errorLine1=" public static final Account ACCOUNT_DEFAULT = new Account("
+ errorLine2=" ~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/Fixtures.java"
+ line="57"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Cast from `Account` to `Parcelable` requires API level 5 (current min is 1)"
+ errorLine1=" out.writeParcelable(account, flags);"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/tx/GetAccountRemovalAllowedTx.java"
+ line="46"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Cast from `Account` to `Parcelable` requires API level 5 (current min is 1)"
+ errorLine1=" out.writeParcelable(account, flags);"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/tx/GetAuthTokenTx.java"
+ line="54"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Cast from `Account` to `Parcelable` requires API level 5 (current min is 1)"
+ errorLine1=" out.writeParcelable(account, flags);"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/tx/HasFeaturesTx.java"
+ line="57"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Cast from `Account` to `Parcelable` requires API level 5 (current min is 1)"
+ errorLine1=" out.writeParcelable(account, flags);"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartUpdateCredentialsSessionTx.java"
+ line="50"
+ column="29"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Class requires API level 5 (current min is 1): `android.accounts.AbstractAccountAuthenticator`"
+ errorLine1="public class TestAccountAuthenticator extends AbstractAccountAuthenticator {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="39"
+ column="47"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 5 (current min is 1): `new android.accounts.AbstractAccountAuthenticator`"
+ errorLine1=" super(context);"
+ errorLine2=" ~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="47"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Cast from `AccountAuthenticatorResponse` to `Parcelable` requires API level 5 (current min is 1)"
+ errorLine1=" intent.putExtra(Fixtures.KEY_CALLBACK, response);"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="89"
+ column="52"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 5 (current min is 1): `android.accounts.AccountAuthenticatorResponse#onResult`"
+ errorLine1=" response.onResult(result);"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="101"
+ column="26"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#type`"
+ errorLine1=" if (!mAccountType.equals(account.type)) {"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="111"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#name`"
+ errorLine1=" if (account.name.startsWith(Fixtures.PREFIX_NAME_SUCCESS)) {"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="120"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#name`"
+ errorLine1=" result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="123"
+ column="63"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#type`"
+ errorLine1=" result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="124"
+ column="63"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#name`"
+ errorLine1=" } else if (account.name.startsWith(Fixtures.PREFIX_NAME_INTERVENE)) {"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="125"
+ column="20"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#name`"
+ errorLine1=" eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="129"
+ column="82"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#type`"
+ errorLine1=" eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type);"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="130"
+ column="82"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Cast from `AccountAuthenticatorResponse` to `Parcelable` requires API level 5 (current min is 1)"
+ errorLine1=" intent.putExtra(Fixtures.KEY_CALLBACK, response);"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="135"
+ column="52"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 5 (current min is 1): `android.accounts.AccountAuthenticatorResponse#onResult`"
+ errorLine1=" response.onResult(result);"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="147"
+ column="26"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#type`"
+ errorLine1=" if (!mAccountType.equals(account.type)) {"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="158"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#name`"
+ errorLine1=" if (account.name.startsWith(Fixtures.PREFIX_NAME_SUCCESS)) {"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="167"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#name`"
+ errorLine1=" result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="174"
+ column="63"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#type`"
+ errorLine1=" result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="175"
+ column="63"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#name`"
+ errorLine1=" } else if (account.name.startsWith(Fixtures.PREFIX_NAME_INTERVENE)) {"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="176"
+ column="20"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#name`"
+ errorLine1=" eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="184"
+ column="82"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#type`"
+ errorLine1=" eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type);"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="185"
+ column="82"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Cast from `AccountAuthenticatorResponse` to `Parcelable` requires API level 5 (current min is 1)"
+ errorLine1=" intent.putExtra(Fixtures.KEY_CALLBACK, response);"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="190"
+ column="52"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 5 (current min is 1): `android.accounts.AccountAuthenticatorResponse#onResult`"
+ errorLine1=" response.onResult(result);"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="203"
+ column="26"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#type`"
+ errorLine1=" if (!mAccountType.equals(account.type)) {"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="222"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#name`"
+ errorLine1=" if (account.name.startsWith(Fixtures.PREFIX_NAME_SUCCESS)) {"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="231"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#name`"
+ errorLine1=" result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="233"
+ column="63"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#type`"
+ errorLine1=" result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="234"
+ column="63"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#name`"
+ errorLine1=" } else if (account.name.startsWith(Fixtures.PREFIX_NAME_INTERVENE)) {"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="235"
+ column="20"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#name`"
+ errorLine1=" eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="238"
+ column="82"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#type`"
+ errorLine1=" eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type);"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="239"
+ column="82"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Cast from `AccountAuthenticatorResponse` to `Parcelable` requires API level 5 (current min is 1)"
+ errorLine1=" intent.putExtra(Fixtures.KEY_CALLBACK, response);"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="244"
+ column="52"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 5 (current min is 1): `android.accounts.AccountAuthenticatorResponse#onResult`"
+ errorLine1=" response.onResult(result);"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="256"
+ column="26"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#type`"
+ errorLine1=" if (!mAccountType.equals(account.type)) {"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="266"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#name`"
+ errorLine1=" if (account.name.startsWith(Fixtures.PREFIX_NAME_SUCCESS)) {"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="274"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#name`"
+ errorLine1=" } else if (account.name.startsWith(Fixtures.PREFIX_NAME_INTERVENE)) {"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="277"
+ column="20"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Cast from `AccountAuthenticatorResponse` to `Parcelable` requires API level 5 (current min is 1)"
+ errorLine1=" intent.putExtra(Fixtures.KEY_CALLBACK, response);"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="284"
+ column="52"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 5 (current min is 1): `android.accounts.AccountAuthenticatorResponse#onResult`"
+ errorLine1=" response.onResult(result);"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="295"
+ column="26"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#type`"
+ errorLine1=" if (!mAccountType.equals(account.type)) {"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAccountAuthenticator.java"
+ line="365"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 5 (current min is 1): `android.accounts.AccountAuthenticatorResponse#onResult`"
+ errorLine1=" response.onResult(result.getExtras());"
+ errorLine2=" ~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestAuthenticatorActivity.java"
+ line="33"
+ column="22"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Class requires API level 5 (current min is 1): `android.accounts.AbstractAccountAuthenticator`"
+ errorLine1="public class TestDefaultAuthenticator extends AbstractAccountAuthenticator {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestDefaultAuthenticator.java"
+ line="34"
+ column="47"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 5 (current min is 1): `new android.accounts.AbstractAccountAuthenticator`"
+ errorLine1=" super(context);"
+ errorLine2=" ~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestDefaultAuthenticator.java"
+ line="39"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#type`"
+ errorLine1=" if (!mAccountType.equals(account.type)) {"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestDefaultAuthenticator.java"
+ line="108"
+ column="34"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#name`"
+ errorLine1=" result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestDefaultAuthenticator.java"
+ line="112"
+ column="59"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 5 (current min is 1): `android.accounts.Account#type`"
+ errorLine1=" result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);"
+ errorLine2=" ~~~~~~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/TestDefaultAuthenticator.java"
+ line="113"
+ column="59"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Cast from `Account` to `Parcelable` requires API level 5 (current min is 1)"
+ errorLine1=" out.writeParcelable(account, flags);"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="cts/tests/tests/accounts/common/src/android/accounts/cts/common/tx/UpdateCredentialsTx.java"
+ line="54"
+ column="29"/>
+ </issue>
+
+</issues>
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 92e351a..2b68ac1 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
@@ -57,6 +57,7 @@
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseLongArray;
+import android.view.KeyEvent;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -199,7 +200,7 @@
private void launchSubActivity(Class<? extends Activity> clazz) {
final Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setClassName(mTargetPackage, clazz.getName());
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
mUiDevice.wait(Until.hasObject(By.clazz(clazz)), TIMEOUT);
}
@@ -1073,7 +1074,11 @@
SparseArray<AggrAllEventsData> baseAggr = getAggrEventData();
// First test -- put device to sleep and make sure we see this event.
- mUiDevice.sleep();
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ mUiDevice.pressKeyCode(KeyEvent.KEYCODE_SLEEP);
+ } else {
+ mUiDevice.sleep();
+ }
// Do we have one event, going in to non-interactive mode?
events = waitForEventCount(INTERACTIVE_EVENTS, startTime, 1);
diff --git a/tests/tests/appop/Android.bp b/tests/tests/appop/Android.bp
index 48f9647..3d8c1d5 100644
--- a/tests/tests/appop/Android.bp
+++ b/tests/tests/appop/Android.bp
@@ -32,6 +32,7 @@
header_libs: ["jni_headers"],
shared_libs: [
"libbinder",
+ "libpermission",
"libutils",
"liblog",
],
@@ -79,6 +80,7 @@
"libnetdutils",
"libnetworkstatsfactorytestjni",
"libpackagelistparser",
+ "libpermission",
"libpcre2",
"libprocessgroup",
"libselinux",
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/Bar.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/Bar.aidl
index 99ba6b5..2aaf974 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/Bar.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/Bar.aidl
@@ -2,13 +2,14 @@
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ByteEnum.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ByteEnum.aidl
index 16c6e1b..944573e 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ByteEnum.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ByteEnum.aidl
@@ -1,14 +1,30 @@
+/*
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ExtendableParcelable.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ExtendableParcelable.aidl
index 6646ba0..dbbb82c 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ExtendableParcelable.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ExtendableParcelable.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/FixedSize.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/FixedSize.aidl
index e7a32f2..f4908e2 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/FixedSize.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/FixedSize.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/Foo.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/Foo.aidl
index ddb6e8b..5e260ff 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/Foo.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/Foo.aidl
@@ -2,13 +2,14 @@
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/GenericBar.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/GenericBar.aidl
index 1d9103b..7cab936 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/GenericBar.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/GenericBar.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
@@ -16,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package test_package;
-parcelable GenericBar {
+parcelable GenericBar<T> {
int a;
test_package.GenericFoo<int,test_package.Bar,test_package.IntEnum> shouldBeGenericFoo;
}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/GenericFoo.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/GenericFoo.aidl
index 9bc86c1..8929c65 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/GenericFoo.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/GenericFoo.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
@@ -16,7 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package test_package;
-parcelable GenericFoo {
+parcelable GenericFoo<T, U, V> {
int a;
int b;
}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/IEmpty.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/IEmpty.aidl
index 5a27b19..1717e58 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/IEmpty.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/IEmpty.aidl
@@ -1,14 +1,30 @@
+/*
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ITest.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ITest.aidl
index 7cd58e7..020c24f 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ITest.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/ITest.aidl
@@ -1,14 +1,30 @@
+/*
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/IntEnum.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/IntEnum.aidl
index f889ec4..92ce575 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/IntEnum.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/IntEnum.aidl
@@ -1,14 +1,30 @@
+/*
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/LongEnum.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/LongEnum.aidl
index b03c85c..4156557 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/LongEnum.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/LongEnum.aidl
@@ -1,14 +1,30 @@
+/*
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/MyExt.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/MyExt.aidl
index 3525284..c054eeb 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/MyExt.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/MyExt.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/RegularPolygon.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/RegularPolygon.aidl
index 8fdd8c84b..3eab12e 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/RegularPolygon.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/RegularPolygon.aidl
@@ -1,14 +1,30 @@
+/*
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/SimpleUnion.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/SimpleUnion.aidl
index e7fc95c..767b5ae 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/SimpleUnion.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/aidl_api/libbinder_ndk_test_interface/current/test_package/SimpleUnion.aidl
@@ -2,13 +2,14 @@
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
diff --git a/tests/tests/bionic/Android.build.copy.libs.mk b/tests/tests/bionic/Android.build.copy.libs.mk
index 8900a75..628eeed 100644
--- a/tests/tests/bionic/Android.build.copy.libs.mk
+++ b/tests/tests/bionic/Android.build.copy.libs.mk
@@ -22,6 +22,12 @@
elftls_dlopen_ie_error_helper/elftls_dlopen_ie_error_helper \
exec_linker_helper/exec_linker_helper \
exec_linker_helper_lib.so \
+ heap_tagging_async_helper/heap_tagging_async_helper \
+ heap_tagging_disabled_helper/heap_tagging_disabled_helper \
+ heap_tagging_static_sync_helper/heap_tagging_static_sync_helper \
+ heap_tagging_static_async_helper/heap_tagging_static_async_helper \
+ heap_tagging_static_disabled_helper/heap_tagging_static_disabled_helper \
+ heap_tagging_sync_helper/heap_tagging_sync_helper \
inaccessible_libs/libtestshared.so \
inaccessible_libs/libtestshared.so \
ld_config_test_helper/ld_config_test_helper \
diff --git a/tests/tests/carrierapi/Android.bp b/tests/tests/carrierapi/Android.bp
index 5f5b61d..32b10e5 100644
--- a/tests/tests/carrierapi/Android.bp
+++ b/tests/tests/carrierapi/Android.bp
@@ -21,8 +21,8 @@
defaults: ["cts_defaults"],
static_libs: [
"androidx.test.uiautomator_uiautomator",
- "ctstestrunner-axt",
"compatibility-device-util-axt",
+ "ctstestrunner-axt",
"junit",
"truth-prebuilt",
],
@@ -34,8 +34,8 @@
"general-tests",
],
libs: [
- "android.test.runner",
"android.test.base",
+ "android.test.runner",
],
// This APK must be signed to match the test SIM's cert whitelist.
// While "testkey" is the default, there are different per-device testkeys, so
diff --git a/tests/tests/carrierapi/AndroidTest.xml b/tests/tests/carrierapi/AndroidTest.xml
index 8d1174b..9b6d4fe 100644
--- a/tests/tests/carrierapi/AndroidTest.xml
+++ b/tests/tests/carrierapi/AndroidTest.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
<configuration description="Config for CTS Carrier APIs test cases">
- <option name="test-suite-tag" value="cts" />
+ <option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/ApnDatabaseTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/ApnDatabaseTest.java
index 91ba3fc..59794c5 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/ApnDatabaseTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/ApnDatabaseTest.java
@@ -15,22 +15,19 @@
*/
package android.carrierapi.cts;
-import static junit.framework.TestCase.assertEquals;
+import static com.google.common.truth.Truth.assertWithMessage;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
import android.content.ContentResolver;
import android.content.ContentValues;
-import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.provider.Telephony.Carriers;
import android.util.Log;
-import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
@@ -42,17 +39,16 @@
import java.util.Map;
/**
- * Build, install and run the tests by running the commands below:
- * make cts -j64
- * cts-tradefed run cts -m CtsCarrierApiTestCases --test android.carrierapi.cts.ApnDatabaseTest
+ * Unit tests for the APN database exposed by {@link Carriers}.
+ *
+ * <p>Test using `atest CtsCarrierApiTestCases:ApnDatabaseTest` or `make cts -j64 && cts-tradefed
+ * run cts -m CtsCarrierApiTestCases --test android.carrierapi.cts.ApnDatabaseTest`
*/
@RunWith(AndroidJUnit4.class)
-public class ApnDatabaseTest {
+public class ApnDatabaseTest extends BaseCarrierApiTest {
private static final String TAG = "ApnDatabaseTest";
private ContentResolver mContentResolver;
- private PackageManager mPackageManager;
- private boolean mHasCellular;
private static final String NAME = "carrierName";
private static final String APN = "apn";
@@ -72,25 +68,28 @@
private static final String NETWORK_TYPE_BITMASK = "0";
private static final String BEARER = "0";
- private static final Map<String, String> APN_MAP = new HashMap<String,String>() {{
- put(Carriers.NAME, NAME);
- put(Carriers.APN, APN);
- put(Carriers.PROXY, PROXY);
- put(Carriers.PORT, PORT);
- put(Carriers.MMSC, MMSC);
- put(Carriers.MMSPROXY, MMSPROXY);
- put(Carriers.MMSPORT, MMSPORT);
- put(Carriers.NUMERIC, NUMERIC);
- put(Carriers.USER, USER);
- put(Carriers.PASSWORD, PASSWORD);
- put(Carriers.AUTH_TYPE, AUTH_TYPE);
- put(Carriers.TYPE, TYPE);
- put(Carriers.PROTOCOL, PROTOCOL);
- put(Carriers.ROAMING_PROTOCOL, ROAMING_PROTOCOL);
- put(Carriers.CARRIER_ENABLED, CARRIER_ENABLED);
- put(Carriers.NETWORK_TYPE_BITMASK, NETWORK_TYPE_BITMASK);
- put(Carriers.BEARER, BEARER);
- }};
+ private static final Map<String, String> APN_MAP =
+ new HashMap<String, String>() {
+ {
+ put(Carriers.NAME, NAME);
+ put(Carriers.APN, APN);
+ put(Carriers.PROXY, PROXY);
+ put(Carriers.PORT, PORT);
+ put(Carriers.MMSC, MMSC);
+ put(Carriers.MMSPROXY, MMSPROXY);
+ put(Carriers.MMSPORT, MMSPORT);
+ put(Carriers.NUMERIC, NUMERIC);
+ put(Carriers.USER, USER);
+ put(Carriers.PASSWORD, PASSWORD);
+ put(Carriers.AUTH_TYPE, AUTH_TYPE);
+ put(Carriers.TYPE, TYPE);
+ put(Carriers.PROTOCOL, PROTOCOL);
+ put(Carriers.ROAMING_PROTOCOL, ROAMING_PROTOCOL);
+ put(Carriers.CARRIER_ENABLED, CARRIER_ENABLED);
+ put(Carriers.NETWORK_TYPE_BITMASK, NETWORK_TYPE_BITMASK);
+ put(Carriers.BEARER, BEARER);
+ }
+ };
// Faked network type bitmask and its compatible bearer bitmask.
private static final int NETWORK_TYPE_BITMASK_NUMBER = 1 << (13 - 1);
@@ -98,29 +97,16 @@
@Before
public void setUp() throws Exception {
- mContentResolver = InstrumentationRegistry.getContext().getContentResolver();
- mPackageManager = InstrumentationRegistry.getContext().getPackageManager();
- // Checks whether the cellular stack should be running on this device.
- mHasCellular = mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
- if (!mHasCellular) {
- Log.e(TAG, "No cellular support, all tests will be skipped.");
- }
- }
-
- private void failMessage() {
- fail("This test requires a SIM card with carrier privilege rule on it.\n" +
- "Visit https://source.android.com/devices/tech/config/uicc.html");
+ mContentResolver = getContext().getContentResolver();
}
/**
- * Test inserting, querying, updating and deleting values in carriers table.
- * Verify that the inserted values match the result of the query and are deleted.
+ * Test inserting, querying, updating and deleting values in carriers table. Verify that the
+ * inserted values match the result of the query and are deleted.
*/
@Test
public void testValidCase() {
- if (!mHasCellular) return;
Uri uri = Carriers.CONTENT_URI;
- // CONTENT_URI = Uri.parse("content://telephony/carriers");
// Create A set of column_name/value pairs to add to the database.
ContentValues contentValues = makeDefaultContentValues();
@@ -128,69 +114,84 @@
// Insert the value into database.
Log.d(TAG, "testInsertCarriers Inserting contentValues: " + contentValues.toString());
Uri newUri = mContentResolver.insert(uri, contentValues);
- assertNotNull("Failed to insert to table", newUri);
+ assertWithMessage("Failed to insert to table").that(newUri).isNotNull();
// Get the values in table.
final String selection = Carriers.NUMERIC + "=?";
- String[] selectionArgs = { NUMERIC };
+ String[] selectionArgs = {NUMERIC};
String[] apnProjection = APN_MAP.keySet().toArray(new String[APN_MAP.size()]);
- Log.d(TAG, "testInsertCarriers query projection: " + Arrays.toString(apnProjection)
- + "\ntestInsertCarriers selection: " + selection
- + "\ntestInsertCarriers selectionArgs: " + Arrays.toString(selectionArgs));
- Cursor cursor = mContentResolver.query(
- uri, apnProjection, selection, selectionArgs, null);
+ Log.d(
+ TAG,
+ "testInsertCarriers query projection: "
+ + Arrays.toString(apnProjection)
+ + "\ntestInsertCarriers selection: "
+ + selection
+ + "\ntestInsertCarriers selectionArgs: "
+ + Arrays.toString(selectionArgs));
+ Cursor cursor =
+ mContentResolver.query(uri, apnProjection, selection, selectionArgs, null);
// Verify that the inserted value match the results of the query
- assertNotNull("Failed to query the table", cursor);
- assertEquals("Unexpected number of APNs returned by cursor",
- 1, cursor.getCount());
+ assertWithMessage("Failed to query the table").that(cursor).isNotNull();
+ assertWithMessage("Unexpected number of APNs returned by cursor")
+ .that(cursor.getCount())
+ .isEqualTo(1);
cursor.moveToFirst();
- for (Map.Entry<String, String> entry: APN_MAP.entrySet()) {
- assertEquals(
- "Unexpected value returned by cursor",
- cursor.getString(cursor.getColumnIndex(entry.getKey())), entry.getValue());
+ for (Map.Entry<String, String> entry : APN_MAP.entrySet()) {
+ assertWithMessage("Unexpected value returned by cursor")
+ .that(cursor.getString(cursor.getColumnIndex(entry.getKey())))
+ .isEqualTo(entry.getValue());
}
// update the apn
final String newApn = "newapn";
Log.d(TAG, "Update the APN field to: " + newApn);
contentValues.put(Carriers.APN, newApn);
- final int updateCount = mContentResolver.update(uri, contentValues, selection,
- selectionArgs);
- assertEquals("Unexpected number of rows updated", 1, updateCount);
+ final int updateCount =
+ mContentResolver.update(uri, contentValues, selection, selectionArgs);
+ assertWithMessage("Unexpected number of rows updated").that(updateCount).isEqualTo(1);
// Verify the updated value
cursor = mContentResolver.query(uri, apnProjection, selection, selectionArgs, null);
- assertNotNull("Failed to query the table", cursor);
- assertEquals("Unexpected number of APNs returned by cursor", 1, cursor.getCount());
+ assertWithMessage("Failed to query the table").that(cursor).isNotNull();
+ assertWithMessage("Unexpected number of APNs returned by cursor")
+ .that(cursor.getCount())
+ .isEqualTo(1);
cursor.moveToFirst();
- assertEquals("Unexpected value returned by cursor",
- cursor.getString(cursor.getColumnIndex(Carriers.APN)), newApn);
+ assertWithMessage("Unexpected value returned by cursor")
+ .that(cursor.getString(cursor.getColumnIndex(Carriers.APN)))
+ .isEqualTo(newApn);
// delete test content
final String selectionToDelete = Carriers.NUMERIC + "=?";
- String[] selectionArgsToDelete = { NUMERIC };
- Log.d(TAG, "testInsertCarriers deleting selection: " + selectionToDelete
- + "testInsertCarriers selectionArgs: " + Arrays.toString(selectionArgs));
- int numRowsDeleted = mContentResolver.delete(
- uri, selectionToDelete, selectionArgsToDelete);
- assertEquals("Unexpected number of rows deleted",1, numRowsDeleted);
+ String[] selectionArgsToDelete = {NUMERIC};
+ Log.d(
+ TAG,
+ "testInsertCarriers deleting selection: "
+ + selectionToDelete
+ + "testInsertCarriers selectionArgs: "
+ + Arrays.toString(selectionArgs));
+ int numRowsDeleted =
+ mContentResolver.delete(uri, selectionToDelete, selectionArgsToDelete);
+ assertWithMessage("Unexpected number of rows deleted")
+ .that(numRowsDeleted)
+ .isEqualTo(1);
// verify that deleted values are gone
cursor = mContentResolver.query(uri, apnProjection, selection, selectionArgs, null);
- assertEquals("Unexpected number of rows deleted", 0, cursor.getCount());
+ assertWithMessage("Unexpected number of rows deleted")
+ .that(cursor.getCount())
+ .isEqualTo(0);
} catch (SecurityException e) {
- failMessage();
+ fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
}
}
@Test
public void testQueryConflictCase() {
- if (!mHasCellular) return;
String invalidColumn = "random";
Uri uri = Carriers.CONTENT_URI;
- // CONTENT_URI = Uri.parse("content://telephony/carriers");
- // Create A set of column_name/value pairs to add to the database.
+ // Create a set of column_name/value pairs to add to the database.
ContentValues contentValues = new ContentValues();
contentValues.put(Carriers.NAME, NAME);
contentValues.put(Carriers.APN, APN);
@@ -202,50 +203,57 @@
// Insert the value into database.
Log.d(TAG, "testInsertCarriers Inserting contentValues: " + contentValues.toString());
Uri newUri = mContentResolver.insert(uri, contentValues);
- assertNotNull("Failed to insert to table", newUri);
+ assertWithMessage("Failed to insert to table").that(newUri).isNotNull();
// Try to get the value with invalid selection
- final String[] testProjection =
- {
- Carriers.NAME,
- Carriers.APN,
- Carriers.PORT,
- Carriers.PROTOCOL,
- Carriers.NUMERIC,
- };
+ final String[] testProjection = {
+ Carriers.NAME, Carriers.APN, Carriers.PORT, Carriers.PROTOCOL, Carriers.NUMERIC,
+ };
final String selection = invalidColumn + "=?";
- String[] selectionArgs = { invalidColumn };
- Log.d(TAG, "testInsertCarriers query projection: " + Arrays.toString(testProjection)
- + "\ntestInsertCarriers selection: " + selection
- + "\ntestInsertCarriers selectionArgs: " + Arrays.toString(selectionArgs));
- Cursor cursor = mContentResolver.query(
- uri, testProjection, selection, selectionArgs, null);
- assertNull("Failed to query the table",cursor);
+ String[] selectionArgs = {invalidColumn};
+ Log.d(
+ TAG,
+ "testInsertCarriers query projection: "
+ + Arrays.toString(testProjection)
+ + "\ntestInsertCarriers selection: "
+ + selection
+ + "\ntestInsertCarriers selectionArgs: "
+ + Arrays.toString(selectionArgs));
+ Cursor cursor =
+ mContentResolver.query(uri, testProjection, selection, selectionArgs, null);
+ assertWithMessage("Failed to query the table").that(cursor).isNull();
// delete test content
final String selectionToDelete = Carriers.NAME + "=?";
- String[] selectionArgsToDelete = { NAME };
- Log.d(TAG, "testInsertCarriers deleting selection: " + selectionToDelete
- + "testInsertCarriers selectionArgs: " + Arrays.toString(selectionArgs));
- int numRowsDeleted = mContentResolver.delete(
- uri, selectionToDelete, selectionArgsToDelete);
- assertEquals("Unexpected number of rows deleted", 1, numRowsDeleted);
+ String[] selectionArgsToDelete = {NAME};
+ Log.d(
+ TAG,
+ "testInsertCarriers deleting selection: "
+ + selectionToDelete
+ + "testInsertCarriers selectionArgs: "
+ + Arrays.toString(selectionArgs));
+ int numRowsDeleted =
+ mContentResolver.delete(uri, selectionToDelete, selectionArgsToDelete);
+ assertWithMessage("Unexpected number of rows deleted")
+ .that(numRowsDeleted)
+ .isEqualTo(1);
// verify that deleted values are gone
- cursor = mContentResolver.query(
- uri, testProjection, selectionToDelete, selectionArgsToDelete, null);
- assertEquals("Unexpected number of rows deleted", 0, cursor.getCount());
+ cursor =
+ mContentResolver.query(
+ uri, testProjection, selectionToDelete, selectionArgsToDelete, null);
+ assertWithMessage("Unexpected number of rows deleted")
+ .that(cursor.getCount())
+ .isEqualTo(0);
} catch (SecurityException e) {
- failMessage();
+ fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
}
}
@Test
public void testUpdateConflictCase() {
- if (!mHasCellular) return;
Uri uri = Carriers.CONTENT_URI;
- // CONTENT_URI = Uri.parse("content://telephony/carriers");
- // Create A set of column_name/value pairs to add to the database.
+ // Create a set of column_name/value pairs to add to the database.
ContentValues contentValues = new ContentValues();
contentValues.put(Carriers.NAME, NAME);
contentValues.put(Carriers.APN, APN);
@@ -257,63 +265,69 @@
// Insert the value into database.
Log.d(TAG, "testInsertCarriers Inserting contentValues: " + contentValues.toString());
Uri newUri = mContentResolver.insert(uri, contentValues);
- assertNotNull("Failed to insert to table", newUri);
+ assertWithMessage("Failed to insert to table").that(newUri).isNotNull();
// Try to get the value with invalid selection
- final String[] testProjection =
- {
- Carriers.NAME,
- Carriers.APN,
- Carriers.PORT,
- Carriers.PROTOCOL,
- Carriers.NUMERIC,
- };
+ final String[] testProjection = {
+ Carriers.NAME, Carriers.APN, Carriers.PORT, Carriers.PROTOCOL, Carriers.NUMERIC,
+ };
String selection = Carriers.NAME + "=?";
- String[] selectionArgs = { NAME };
- Log.d(TAG, "testInsertCarriers query projection: " + Arrays.toString(testProjection)
- + "\ntestInsertCarriers selection: " + selection
- + "\ntestInsertCarriers selectionArgs: " + Arrays.toString(selectionArgs));
- Cursor cursor = mContentResolver.query(
- uri, testProjection, selection, selectionArgs, null);
- assertEquals("Unexpected number of APNs returned by cursor",
- 1, cursor.getCount());
+ String[] selectionArgs = {NAME};
+ Log.d(
+ TAG,
+ "testInsertCarriers query projection: "
+ + Arrays.toString(testProjection)
+ + "\ntestInsertCarriers selection: "
+ + selection
+ + "\ntestInsertCarriers selectionArgs: "
+ + Arrays.toString(selectionArgs));
+ Cursor cursor =
+ mContentResolver.query(uri, testProjection, selection, selectionArgs, null);
+ assertWithMessage("Unexpected number of APNs returned by cursor")
+ .that(cursor.getCount())
+ .isEqualTo(1);
// Update the table with invalid column
String invalidColumn = "random";
contentValues.put(invalidColumn, invalidColumn);
- try {
- mContentResolver.update(uri, contentValues, selection, selectionArgs);
- fail();
- } catch (SQLiteException e) {
- // Expected: If there's no such a column, an exception will be thrown and the
- // Activity Manager will kill this process shortly.
- }
+ // Expected: If there's no such a column, an exception will be thrown and
+ // ActivityManager will kill this process shortly.
+ assertThrows(
+ SQLiteException.class,
+ () -> mContentResolver.update(uri, contentValues, selection, selectionArgs));
// delete test content
final String selectionToDelete = Carriers.NAME + "=?";
- String[] selectionArgsToDelete = { NAME };
- Log.d(TAG, "testInsertCarriers deleting selection: " + selectionToDelete
- + "testInsertCarriers selectionArgs: " + Arrays.toString(selectionArgs));
- int numRowsDeleted = mContentResolver.delete(
- uri, selectionToDelete, selectionArgsToDelete);
- assertEquals("Unexpected number of rows deleted", 1, numRowsDeleted);
+ String[] selectionArgsToDelete = {NAME};
+ Log.d(
+ TAG,
+ "testInsertCarriers deleting selection: "
+ + selectionToDelete
+ + "testInsertCarriers selectionArgs: "
+ + Arrays.toString(selectionArgs));
+ int numRowsDeleted =
+ mContentResolver.delete(uri, selectionToDelete, selectionArgsToDelete);
+ assertWithMessage("Unexpected number of rows deleted")
+ .that(numRowsDeleted)
+ .isEqualTo(1);
// verify that deleted values are gone
- cursor = mContentResolver.query(
- uri, testProjection, selectionToDelete, selectionArgsToDelete, null);
- assertEquals("Unexpected number of rows deleted", 0, cursor.getCount());
+ cursor =
+ mContentResolver.query(
+ uri, testProjection, selectionToDelete, selectionArgsToDelete, null);
+ assertWithMessage("Unexpected number of rows deleted")
+ .that(cursor.getCount())
+ .isEqualTo(0);
} catch (SecurityException e) {
- failMessage();
+ fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
}
}
@Test
public void testDeleteConflictCase() {
- if (!mHasCellular) return;
String invalidColumn = "random";
Uri uri = Carriers.CONTENT_URI;
- // CONTENT_URI = Uri.parse("content://telephony/carriers");
- // Create A set of column_name/value pairs to add to the database.
+ // Create a set of column_name/value pairs to add to the database.
ContentValues contentValues = new ContentValues();
contentValues.put(Carriers.NAME, NAME);
contentValues.put(Carriers.APN, APN);
@@ -325,68 +339,84 @@
// Insert the value into database.
Log.d(TAG, "testInsertCarriers Inserting contentValues: " + contentValues.toString());
Uri newUri = mContentResolver.insert(uri, contentValues);
- assertNotNull("Failed to insert to table", newUri);
+ assertWithMessage("Failed to insert to table").that(newUri).isNotNull();
// Get the values in table.
- final String[] testProjection =
- {
- Carriers.NAME,
- Carriers.APN,
- Carriers.PORT,
- Carriers.PROTOCOL,
- Carriers.NUMERIC,
- };
+ final String[] testProjection = {
+ Carriers.NAME, Carriers.APN, Carriers.PORT, Carriers.PROTOCOL, Carriers.NUMERIC,
+ };
String selection = Carriers.NAME + "=?";
- String[] selectionArgs = { NAME };
- Log.d(TAG, "testInsertCarriers query projection: " + Arrays.toString(testProjection)
- + "\ntestInsertCarriers selection: " + selection
- + "\ntestInsertCarriers selectionArgs: " + Arrays.toString(selectionArgs));
- Cursor cursor = mContentResolver.query(
- uri, testProjection, selection, selectionArgs, null);
- assertEquals("Unexpected number of APNs returned by cursor", 1, cursor.getCount());
+ String[] selectionArgs = {NAME};
+ Log.d(
+ TAG,
+ "testInsertCarriers query projection: "
+ + Arrays.toString(testProjection)
+ + "\ntestInsertCarriers selection: "
+ + selection
+ + "\ntestInsertCarriers selectionArgs: "
+ + Arrays.toString(selectionArgs));
+ Cursor cursor =
+ mContentResolver.query(uri, testProjection, selection, selectionArgs, null);
+ assertWithMessage("Unexpected number of APNs returned by cursor")
+ .that(cursor.getCount())
+ .isEqualTo(1);
// try to delete with invalid selection
- String selectionToDelete = invalidColumn + "=?";
- String[] selectionArgsToDelete = { invalidColumn };
- Log.d(TAG, "testInsertCarriers deleting selection: " + selectionToDelete
- + "testInsertCarriers selectionArgs: " + Arrays.toString(selectionArgs));
+ String invalidSelectionToDelete = invalidColumn + "=?";
+ String[] invalidSelectionArgsToDelete = {invalidColumn};
+ Log.d(
+ TAG,
+ "testInsertCarriers deleting selection: "
+ + invalidSelectionToDelete
+ + "testInsertCarriers selectionArgs: "
+ + Arrays.toString(selectionArgs));
- try {
- mContentResolver.delete(uri, selectionToDelete, selectionArgsToDelete);
- fail();
- } catch (SQLiteException e) {
- // Expected: If there's no such a column, an exception will be thrown and the
- // Activity Manager will kill this process shortly.
- }
+ // Expected: If there's no such a column, an exception will be thrown and
+ // ActivityManager will kill this process shortly.
+ assertThrows(
+ SQLiteException.class,
+ () ->
+ mContentResolver.delete(
+ uri, invalidSelectionToDelete, invalidSelectionArgsToDelete));
// verify that deleted value is still there
selection = Carriers.NAME + "=?";
selectionArgs[0] = NAME;
cursor = mContentResolver.query(uri, testProjection, selection, selectionArgs, null);
- assertEquals("Unexpected number of APNs returned by cursor", 1, cursor.getCount());
+ assertWithMessage("Unexpected number of APNs returned by cursor")
+ .that(cursor.getCount())
+ .isEqualTo(1);
// delete test content
- selectionToDelete = Carriers.NAME + "=?";
- selectionArgsToDelete[0] = NAME;
- Log.d(TAG, "testInsertCarriers deleting selection: " + selectionToDelete
- + "testInsertCarriers selectionArgs: " + Arrays.toString(selectionArgs));
- int numRowsDeleted = mContentResolver.delete(
- uri, selectionToDelete, selectionArgsToDelete);
- assertEquals("Unexpected number of rows deleted", 1, numRowsDeleted);
+ String selectionToDelete = Carriers.NAME + "=?";
+ String[] selectionArgsToDelete = {NAME};
+ Log.d(
+ TAG,
+ "testInsertCarriers deleting selection: "
+ + selectionToDelete
+ + "testInsertCarriers selectionArgs: "
+ + Arrays.toString(selectionArgs));
+ int numRowsDeleted =
+ mContentResolver.delete(uri, selectionToDelete, selectionArgsToDelete);
+ assertWithMessage("Unexpected number of rows deleted")
+ .that(numRowsDeleted)
+ .isEqualTo(1);
// verify that deleted values are gone
cursor = mContentResolver.query(uri, testProjection, selection, selectionArgs, null);
- assertEquals("Unexpected number of rows deleted", 0, cursor.getCount());
+ assertWithMessage("Unexpected number of rows deleted")
+ .that(cursor.getCount())
+ .isEqualTo(0);
} catch (SecurityException e) {
- failMessage();
+ fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
}
}
private ContentValues makeDefaultContentValues() {
ContentValues contentValues = new ContentValues();
- for (Map.Entry<String, String> entry: APN_MAP.entrySet()) {
+ for (Map.Entry<String, String> entry : APN_MAP.entrySet()) {
contentValues.put(entry.getKey(), entry.getValue());
}
return contentValues;
}
-}
\ No newline at end of file
+}
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/BaseCarrierApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/BaseCarrierApiTest.java
new file mode 100644
index 0000000..b0b6504
--- /dev/null
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/BaseCarrierApiTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.carrierapi.cts;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.telephony.TelephonyManager;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.FeatureUtil;
+
+import org.junit.Before;
+
+/**
+ * Common test base to ensure uniform preconditions checking. This class will check for:
+ *
+ * <ol>
+ * <li>{@link android.content.pm.PackageManager#FEATURE_TELEPHONY}
+ * <li>A SIM that grants us carrier privileges is currently active in the device
+ * </ol>
+ *
+ * Just inherit from this class when writing your test, then you are able to assume in the subclass
+ * {@code Before} method that preconditions have all passed. The setup and test methods will not be
+ * executed if preconditions are not met.
+ */
+public abstract class BaseCarrierApiTest {
+ protected static final String NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE =
+ "This test requires a SIM card with carrier privilege rules on it.\n"
+ + "Visit https://source.android.com/devices/tech/config/uicc.html";
+
+ protected Context getContext() {
+ return InstrumentationRegistry.getInstrumentation().getTargetContext();
+ }
+
+ private boolean mPreconditionsSatisfied = false;
+
+ protected boolean werePreconditionsSatisfied() {
+ return mPreconditionsSatisfied;
+ }
+
+ /**
+ * Subclasses do NOT need to explicitly call or override this method. Per the JUnit docs, a
+ * superclass {@code Before} method always executes before a subclass {@code Before} method.
+ *
+ * <p>If preconditions fail, neither the subclass {@code Before} method(s) nor the actual {@code
+ * Test} method will execute, but {@code After} methods will still execute. If a subclass does
+ * work in an {@code After} method, then it should first check {@link
+ * #werePreconditionsSatisfied} and return early without doing any work if it's {@code false}.
+ */
+ @Before
+ public void ensurePreconditionsMet() {
+ mPreconditionsSatisfied = false;
+ // Bail out if no cellular support.
+ assumeTrue(
+ "No cellular support, CarrierAPI."
+ + getClass().getSimpleName()
+ + " cases will be skipped",
+ FeatureUtil.hasTelephony());
+ // We must run with carrier privileges.
+ assertWithMessage(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE)
+ .that(getContext().getSystemService(TelephonyManager.class).hasCarrierPrivileges())
+ .isTrue();
+ mPreconditionsSatisfied = true;
+ }
+}
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/BugreportManagerTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/BugreportManagerTest.java
index 820c27a..f87bb3f 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/BugreportManagerTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/BugreportManagerTest.java
@@ -16,21 +16,19 @@
package android.carrierapi.cts;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
-import android.content.Context;
-import android.content.pm.PackageManager;
import android.os.BugreportManager;
import android.os.BugreportManager.BugreportCallback;
import android.os.BugreportParams;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.platform.test.annotations.SystemUserOnly;
-import android.telephony.TelephonyManager;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -41,6 +39,8 @@
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.Until;
+import com.android.compatibility.common.util.PollingCheck;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -64,11 +64,15 @@
*/
@SystemUserOnly(reason = "BugreportManager requires calls to originate from the primary user")
@RunWith(AndroidJUnit4.class)
-public class BugreportManagerTest {
+public class BugreportManagerTest extends BaseCarrierApiTest {
private static final String TAG = "BugreportManagerTest";
+ // See BugreportManagerServiceImpl#BUGREPORT_SERVICE.
+ private static final String BUGREPORT_SERVICE = "bugreportd";
+
private static final long BUGREPORT_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(10);
private static final long UIAUTOMATOR_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(10);
+ private static final long ONEWAY_CALLBACK_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5);
// This value is defined in dumpstate.cpp:TELEPHONY_REPORT_USER_CONSENT_TIMEOUT_MS. Because the
// consent dialog is so large and important, the user *must* be given at least 2 minutes to read
// it before it times out.
@@ -78,7 +82,6 @@
@Rule public TestName name = new TestName();
- private TelephonyManager mTelephonyManager;
private BugreportManager mBugreportManager;
private File mBugreportFile;
private ParcelFileDescriptor mBugreportFd;
@@ -87,20 +90,9 @@
@Before
public void setUp() throws Exception {
- Context context = InstrumentationRegistry.getContext();
- // Bail out if no cellular support.
- assumeTrue(
- "No cellular support, CarrierAPI.BugreportManagerTest cases will be skipped",
- context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY));
- // Fail the test if we don't have carrier privileges.
- mTelephonyManager = context.getSystemService(TelephonyManager.class);
- assertWithMessage(
- "This test requires a SIM card with carrier privilege rules on it.\n"
- + "Visit https://source.android.com/devices/tech/config/uicc.html")
- .that(mTelephonyManager.hasCarrierPrivileges())
- .isTrue();
- mBugreportManager = context.getSystemService(BugreportManager.class);
+ mBugreportManager = getContext().getSystemService(BugreportManager.class);
+ killCurrentBugreportIfRunning();
mBugreportFile = createTempFile("bugreport_" + name.getMethodName(), ".zip");
mBugreportFd = parcelFd(mBugreportFile);
// Should never be written for anything a carrier app can trigger; several tests assert that
@@ -111,8 +103,11 @@
@After
public void tearDown() throws Exception {
+ if (!werePreconditionsSatisfied()) return;
+
FileUtils.closeQuietly(mBugreportFd);
FileUtils.closeQuietly(mScreenshotFd);
+ killCurrentBugreportIfRunning();
}
@Test
@@ -178,6 +173,13 @@
// Attempting to start a second report immediately gets us a concurrency error.
mBugreportManager.startConnectivityBugreport(bugreportFd2, Runnable::run, callback2);
+ // Since IDumpstateListener#onError is oneway, it's not guaranteed that binder has delivered
+ // the callback to us yet, even though BugreportManagerServiceImpl sends it before returning
+ // from #startBugreport.
+ PollingCheck.check(
+ "No terminal callback received for the second bugreport",
+ ONEWAY_CALLBACK_TIMEOUT_MILLIS,
+ callback2::isDone);
assertThat(callback2.getErrorCode())
.isEqualTo(BugreportCallback.BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS);
@@ -334,6 +336,14 @@
}
}
+ /**
+ * Kills the current bugreport if one is in progress to prevent failing test cases from
+ * cascading into other cases and causing flakes.
+ */
+ private static void killCurrentBugreportIfRunning() throws Exception {
+ runShellCommand("setprop ctl.stop " + BUGREPORT_SERVICE);
+ }
+
/** Allow/deny the consent dialog to sharing bugreport data, or just check existence. */
private enum ConsentReply {
// Touch the positive button.
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
index da46842..1f672db 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
@@ -22,9 +22,13 @@
import static android.telephony.IccOpenLogicalChannelResponse.INVALID_CHANNEL;
import static android.telephony.IccOpenLogicalChannelResponse.STATUS_NO_ERROR;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
+import static com.android.compatibility.common.util.UiccUtil.UiccCertificate.CTS_UICC_2021;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
import android.content.BroadcastReceiver;
import android.content.ContentProviderClient;
@@ -32,8 +36,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
@@ -55,15 +57,21 @@
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.Suppress;
import android.util.Base64;
import android.util.Log;
-import com.android.compatibility.common.util.ShellIdentityUtils;
+import androidx.test.runner.AndroidJUnit4;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
+import com.android.compatibility.common.util.ShellIdentityUtils;
+import com.android.compatibility.common.util.UiccUtil;
+
+import com.google.common.collect.Range;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -78,23 +86,27 @@
import javax.annotation.Nonnull;
+/**
+ * Unit tests for various carrier-related APIs.
+ *
+ * <p>Test using `atest CtsCarrierApiTestCases:CarrierApiTest` or `make cts -j64 && cts-tradefed run
+ * cts -m CtsCarrierApiTestCases --test android.carrierapi.cts.CarrierApiTest`
+ */
// TODO(b/130187425): Split CarrierApiTest apart to have separate test classes for functionality
-public class CarrierApiTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class CarrierApiTest extends BaseCarrierApiTest {
private static final String TAG = "CarrierApiTest";
+
private TelephonyManager mTelephonyManager;
private CarrierConfigManager mCarrierConfigManager;
- private PackageManager mPackageManager;
private SubscriptionManager mSubscriptionManager;
private ContentProviderClient mVoicemailProvider;
private ContentProviderClient mStatusProvider;
private Uri mVoicemailContentUri;
private Uri mStatusContentUri;
- private boolean hasCellular;
private String selfPackageName;
- private String selfCertHash;
private HandlerThread mListenerThread;
- private static final String FiDevCert = "24EB92CBB156B280FA4E1429A6ECEEB6E5C1BFE4";
// The minimum allocatable logical channel number, per TS 102 221 Section 11.1.17.1
private static final int MIN_LOGICAL_CHANNEL = 1;
// The maximum allocatable logical channel number in the standard range, per TS 102 221 Section
@@ -163,37 +175,26 @@
private static final int DSDS_PHONE_COUNT = 2;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mPackageManager = getContext().getPackageManager();
- mTelephonyManager = (TelephonyManager)
- getContext().getSystemService(Context.TELEPHONY_SERVICE);
- hasCellular = hasCellular();
- if (!hasCellular) {
- Log.e(TAG, "No cellular support, all tests will be skipped.");
- return;
- }
-
- mCarrierConfigManager = (CarrierConfigManager)
- getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
- mSubscriptionManager = (SubscriptionManager)
- getContext().getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
- selfPackageName = getContext().getPackageName();
- selfCertHash = getCertHash(selfPackageName);
+ @Before
+ public void setUp() throws Exception {
+ Context context = getContext();
+ mTelephonyManager = context.getSystemService(TelephonyManager.class);
+ mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
+ mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
+ selfPackageName = context.getPackageName();
mVoicemailContentUri = VoicemailContract.Voicemails.buildSourceUri(selfPackageName);
- mVoicemailProvider = getContext().getContentResolver()
- .acquireContentProviderClient(mVoicemailContentUri);
+ mVoicemailProvider =
+ context.getContentResolver().acquireContentProviderClient(mVoicemailContentUri);
mStatusContentUri = VoicemailContract.Status.buildSourceUri(selfPackageName);
- mStatusProvider = getContext().getContentResolver()
- .acquireContentProviderClient(mStatusContentUri);
+ mStatusProvider =
+ context.getContentResolver().acquireContentProviderClient(mStatusContentUri);
mListenerThread = new HandlerThread("CarrierApiTest");
mListenerThread.start();
}
- @Override
+ @After
public void tearDown() throws Exception {
- if (!hasCellular) return;
+ if (!werePreconditionsSatisfied()) return;
mListenerThread.quit();
try {
@@ -202,68 +203,34 @@
} catch (Exception e) {
Log.w(TAG, "Failed to clean up voicemail tables in tearDown", e);
}
- super.tearDown();
}
- /**
- * Checks whether the cellular stack should be running on this device.
- */
- private boolean hasCellular() {
- return mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) &&
- mTelephonyManager.getPhoneCount() > 0;
- }
-
- private boolean isSimCardPresent() {
- return mTelephonyManager.getSimState() != TelephonyManager.SIM_STATE_ABSENT;
- }
-
- private String getCertHash(String pkgName) {
- try {
- PackageInfo pInfo = mPackageManager.getPackageInfo(pkgName,
- PackageManager.GET_SIGNATURES | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
- MessageDigest md = MessageDigest.getInstance("SHA-1");
- return bytesToHexString(md.digest(pInfo.signatures[0].toByteArray()));
- } catch (PackageManager.NameNotFoundException ex) {
- Log.e(TAG, pkgName + " not found", ex);
- } catch (NoSuchAlgorithmException ex) {
- Log.e(TAG, "Algorithm SHA1 is not found.");
- }
- return "";
- }
-
- private void failMessage() {
- if (FiDevCert.equalsIgnoreCase(selfCertHash)) {
- fail("This test requires a Project Fi SIM card.");
- } else {
- fail("This test requires a SIM card with carrier privilege rule on it.\n" +
- "Cert hash: " + selfCertHash + "\n" +
- "Visit https://source.android.com/devices/tech/config/uicc.html");
- }
- }
-
+ @Test
public void testSimCardPresent() {
- if (!hasCellular) return;
- assertTrue("This test requires SIM card.", isSimCardPresent());
+ assertWithMessage("This test requires a SIM card")
+ .that(mTelephonyManager.getSimState())
+ .isNotEqualTo(TelephonyManager.SIM_STATE_ABSENT);
}
+ @Test
public void testHasCarrierPrivileges() {
- if (!hasCellular) return;
- if (!mTelephonyManager.hasCarrierPrivileges()) {
- failMessage();
- }
+ assertWithMessage(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE)
+ .that(mTelephonyManager.hasCarrierPrivileges())
+ .isTrue();
}
private static void assertUpdateAvailableNetworkSuccess(int value) {
- assertEquals(TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS, value);
+ assertThat(value).isEqualTo(TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS);
}
private static void assertUpdateAvailableNetworkNoOpportunisticSubAvailable(int value) {
- assertEquals(
- TelephonyManager.UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE, value);
+ assertThat(value)
+ .isEqualTo(
+ TelephonyManager.UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE);
}
private static void assertSetOpportunisticSubSuccess(int value) {
- assertEquals(TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS, value);
+ assertThat(value).isEqualTo(TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS);
}
private int getFirstActivateCarrierPrivilegedSubscriptionId() {
@@ -272,8 +239,8 @@
mSubscriptionManager.getActiveSubscriptionInfoList();
if (subscriptionInfos != null) {
for (SubscriptionInfo info : subscriptionInfos) {
- TelephonyManager telephonyManager = mTelephonyManager.createForSubscriptionId(
- info.getSubscriptionId());
+ TelephonyManager telephonyManager =
+ mTelephonyManager.createForSubscriptionId(info.getSubscriptionId());
if (telephonyManager.hasCarrierPrivileges()) {
subId = info.getSubscriptionId();
return subId;
@@ -283,15 +250,12 @@
return subId;
}
+ @Test
public void testUpdateAvailableNetworksWithCarrierPrivilege() {
- if (!hasCellular) return;
-
int subIdWithCarrierPrivilege = getFirstActivateCarrierPrivilegedSubscriptionId();
- int activeSubscriptionInfoCount = ShellIdentityUtils.invokeMethodWithShellPermissions(
- mSubscriptionManager, (tm) -> tm.getActiveSubscriptionInfoCount());
- if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
- return;
- }
+ int activeSubscriptionInfoCount =
+ ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mSubscriptionManager, (tm) -> tm.getActiveSubscriptionInfoCount());
if (mTelephonyManager.getPhoneCount() == 1) {
return;
}
@@ -311,42 +275,52 @@
List<String> mccMncs = new ArrayList<String>();
List<Integer> bands = new ArrayList<Integer>();
List<AvailableNetworkInfo> availableNetworkInfos = new ArrayList<AvailableNetworkInfo>();
- Consumer<Integer> callbackSuccess =
- CarrierApiTest::assertUpdateAvailableNetworkSuccess;
+ Consumer<Integer> callbackSuccess = CarrierApiTest::assertUpdateAvailableNetworkSuccess;
Consumer<Integer> callbackNoOpportunisticSubAvailable =
CarrierApiTest::assertUpdateAvailableNetworkNoOpportunisticSubAvailable;
Consumer<Integer> setOpCallbackSuccess = CarrierApiTest::assertSetOpportunisticSubSuccess;
- if (subscriptionInfoList == null || subscriptionInfoList.size() == 0
+ if (subscriptionInfoList == null
+ || subscriptionInfoList.size() == 0
|| !mSubscriptionManager.isActiveSubscriptionId(
subscriptionInfoList.get(0).getSubscriptionId())) {
try {
- AvailableNetworkInfo availableNetworkInfo = new AvailableNetworkInfo(
- subIdWithCarrierPrivilege, AvailableNetworkInfo.PRIORITY_HIGH, mccMncs,
- bands);
+ AvailableNetworkInfo availableNetworkInfo =
+ new AvailableNetworkInfo(
+ subIdWithCarrierPrivilege,
+ AvailableNetworkInfo.PRIORITY_HIGH,
+ mccMncs,
+ bands);
availableNetworkInfos.add(availableNetworkInfo);
// Call updateAvailableNetworks without opportunistic subscription.
// callbackNoOpportunisticSubAvailable is expected to be triggered
// and the return value will be checked against
// UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE
- mTelephonyManager.updateAvailableNetworks(availableNetworkInfos,
- AsyncTask.SERIAL_EXECUTOR, callbackNoOpportunisticSubAvailable);
+ mTelephonyManager.updateAvailableNetworks(
+ availableNetworkInfos,
+ AsyncTask.SERIAL_EXECUTOR,
+ callbackNoOpportunisticSubAvailable);
} finally {
// clear all the operations at the end of test.
availableNetworkInfos.clear();
- mTelephonyManager.updateAvailableNetworks(availableNetworkInfos,
- AsyncTask.SERIAL_EXECUTOR, callbackNoOpportunisticSubAvailable);
+ mTelephonyManager.updateAvailableNetworks(
+ availableNetworkInfos,
+ AsyncTask.SERIAL_EXECUTOR,
+ callbackNoOpportunisticSubAvailable);
}
} else {
// This is case of DSDS phone, one active opportunistic subscription and one
// active primary subscription.
int resultSubId;
try {
- AvailableNetworkInfo availableNetworkInfo = new AvailableNetworkInfo(
- subscriptionInfoList.get(0).getSubscriptionId(),
- AvailableNetworkInfo.PRIORITY_HIGH, mccMncs, bands);
+ AvailableNetworkInfo availableNetworkInfo =
+ new AvailableNetworkInfo(
+ subscriptionInfoList.get(0).getSubscriptionId(),
+ AvailableNetworkInfo.PRIORITY_HIGH,
+ mccMncs,
+ bands);
availableNetworkInfos.add(availableNetworkInfo);
- mTelephonyManager.updateAvailableNetworks(availableNetworkInfos,
- AsyncTask.SERIAL_EXECUTOR, callbackSuccess);
+ mTelephonyManager.updateAvailableNetworks(
+ availableNetworkInfos, AsyncTask.SERIAL_EXECUTOR, callbackSuccess);
// wait for the data change to take effect
waitForMs(500);
// Call setPreferredData and reconfirm with getPreferred data
@@ -357,19 +331,21 @@
// wait for the data change to take effect
waitForMs(500);
resultSubId = mTelephonyManager.getPreferredOpportunisticDataSubscription();
- assertEquals(preferSubId, resultSubId);
+ assertThat(resultSubId).isEqualTo(preferSubId);
} finally {
// clear all the operations at the end of test.
availableNetworkInfos.clear();
- mTelephonyManager.updateAvailableNetworks(availableNetworkInfos,
- AsyncTask.SERIAL_EXECUTOR, callbackSuccess);
+ mTelephonyManager.updateAvailableNetworks(
+ availableNetworkInfos, AsyncTask.SERIAL_EXECUTOR, callbackSuccess);
waitForMs(500);
mTelephonyManager.setPreferredOpportunisticDataSubscription(
- SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false,
- AsyncTask.SERIAL_EXECUTOR, callbackSuccess);
+ SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+ false,
+ AsyncTask.SERIAL_EXECUTOR,
+ callbackSuccess);
waitForMs(500);
resultSubId = mTelephonyManager.getPreferredOpportunisticDataSubscription();
- assertEquals(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, resultSubId);
+ assertThat(resultSubId).isEqualTo(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
}
}
}
@@ -382,107 +358,145 @@
}
}
+ @Test
public void testGetIccAuthentication() {
// EAP-SIM rand is 16 bytes.
String base64Challenge = "ECcTqwuo6OfY8ddFRboD9WM=";
String base64Challenge2 = "EMNxjsFrPCpm+KcgCmQGnwQ=";
- if (!hasCellular) return;
+
try {
- assertNull("getIccAuthentication should return null for empty data.",
- mTelephonyManager.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_AKA, ""));
- String response = mTelephonyManager.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_SIM, base64Challenge);
- assertTrue("Response to EAP-SIM Challenge must not be Null.", response != null);
+ assertWithMessage("getIccAuthentication should return null for empty data.")
+ .that(
+ mTelephonyManager.getIccAuthentication(
+ TelephonyManager.APPTYPE_USIM,
+ TelephonyManager.AUTHTYPE_EAP_AKA,
+ ""))
+ .isNull();
+ String response =
+ mTelephonyManager.getIccAuthentication(
+ TelephonyManager.APPTYPE_USIM,
+ TelephonyManager.AUTHTYPE_EAP_SIM,
+ base64Challenge);
+ assertWithMessage("Response to EAP-SIM Challenge must not be Null.")
+ .that(response)
+ .isNotNull();
// response is base64 encoded. After decoding, the value should be:
// 1 length byte + SRES(4 bytes) + 1 length byte + Kc(8 bytes)
byte[] result = android.util.Base64.decode(response, android.util.Base64.DEFAULT);
- assertTrue("Result length must be 14 bytes.", 14 == result.length);
- String response2 = mTelephonyManager.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
- TelephonyManager.AUTHTYPE_EAP_SIM, base64Challenge2);
- assertTrue("Two responses must be different.", !response.equals(response2));
+ assertThat(result).hasLength(14);
+ String response2 =
+ mTelephonyManager.getIccAuthentication(
+ TelephonyManager.APPTYPE_USIM,
+ TelephonyManager.AUTHTYPE_EAP_SIM,
+ base64Challenge2);
+ assertWithMessage("Two responses must be different")
+ .that(response)
+ .isNotEqualTo(response2);
} catch (SecurityException e) {
- failMessage();
+ fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
}
}
+ @Test
@SystemUserOnly(reason = "b/177921545, broadcast sent only to primary user")
public void testSendDialerSpecialCode() {
- if (!hasCellular) return;
- try {
- IntentReceiver intentReceiver = new IntentReceiver();
- final IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Telephony.Sms.Intents.SECRET_CODE_ACTION);
- intentFilter.addDataScheme("android_secret_code");
- getContext().registerReceiver(intentReceiver, intentFilter);
+ IntentReceiver intentReceiver = new IntentReceiver();
+ final IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Telephony.Sms.Intents.SECRET_CODE_ACTION);
+ intentFilter.addDataScheme("android_secret_code");
+ Context context = getContext();
+ context.registerReceiver(intentReceiver, intentFilter);
+ try {
mTelephonyManager.sendDialerSpecialCode("4636");
- assertTrue("Did not receive expected Intent: " +
- Telephony.Sms.Intents.SECRET_CODE_ACTION,
- intentReceiver.waitForReceive());
+ assertWithMessage(
+ "Did not receive expected Intent: "
+ + Telephony.Sms.Intents.SECRET_CODE_ACTION)
+ .that(intentReceiver.waitForReceive())
+ .isTrue();
} catch (SecurityException e) {
- failMessage();
+ fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
} catch (InterruptedException e) {
Log.d(TAG, "Broadcast receiver wait was interrupted.");
+ } finally {
+ context.unregisterReceiver(intentReceiver);
}
}
+ @Test
public void testSubscriptionInfoListing() {
- if (!hasCellular) return;
try {
- assertTrue("getActiveSubscriptionInfoCount() should be non-zero",
- mSubscriptionManager.getActiveSubscriptionInfoCount() > 0);
+ assertThat(mSubscriptionManager.getActiveSubscriptionInfoCount()).isGreaterThan(0);
List<SubscriptionInfo> subInfoList =
mSubscriptionManager.getActiveSubscriptionInfoList();
- assertNotNull("getActiveSubscriptionInfoList() returned null", subInfoList);
- assertFalse("getActiveSubscriptionInfoList() returned an empty list",
- subInfoList.isEmpty());
+ assertWithMessage("getActiveSubscriptionInfoList() returned null")
+ .that(subInfoList)
+ .isNotNull();
+ assertWithMessage("getActiveSubscriptionInfoList() returned an empty list")
+ .that(subInfoList)
+ .isNotEmpty();
for (SubscriptionInfo info : subInfoList) {
TelephonyManager tm =
mTelephonyManager.createForSubscriptionId(info.getSubscriptionId());
- assertTrue("getActiveSubscriptionInfoList() returned an inaccessible subscription",
- tm.hasCarrierPrivileges());
+ assertWithMessage(
+ "getActiveSubscriptionInfoList() returned an inaccessible"
+ + " subscription")
+ .that(tm.hasCarrierPrivileges())
+ .isTrue();
// Check other APIs to make sure they are accessible and return consistent info.
SubscriptionInfo infoForSlot =
mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(
info.getSimSlotIndex());
- assertNotNull("getActiveSubscriptionInfoForSimSlotIndex() returned null",
- infoForSlot);
- assertEquals(
- "getActiveSubscriptionInfoForSimSlotIndex() returned inconsistent info",
- info.getSubscriptionId(), infoForSlot.getSubscriptionId());
+ assertWithMessage("getActiveSubscriptionInfoForSimSlotIndex() returned null")
+ .that(infoForSlot)
+ .isNotNull();
+ assertWithMessage(
+ "getActiveSubscriptionInfoForSimSlotIndex() returned inconsistent"
+ + " info")
+ .that(infoForSlot.getSubscriptionId())
+ .isEqualTo(info.getSubscriptionId());
SubscriptionInfo infoForSubId =
mSubscriptionManager.getActiveSubscriptionInfo(info.getSubscriptionId());
- assertNotNull("getActiveSubscriptionInfo() returned null", infoForSubId);
- assertEquals("getActiveSubscriptionInfo() returned inconsistent info",
- info.getSubscriptionId(), infoForSubId.getSubscriptionId());
+ assertWithMessage("getActiveSubscriptionInfo() returned null")
+ .that(infoForSubId)
+ .isNotNull();
+ assertWithMessage("getActiveSubscriptionInfo() returned inconsistent info")
+ .that(infoForSubId.getSubscriptionId())
+ .isEqualTo(info.getSubscriptionId());
}
} catch (SecurityException e) {
- failMessage();
+ fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
}
}
+ @Test
public void testCarrierConfigIsAccessible() {
- if (!hasCellular) return;
try {
PersistableBundle bundle = mCarrierConfigManager.getConfig();
- assertNotNull("CarrierConfigManager#getConfig() returned null", bundle);
- assertFalse("CarrierConfigManager#getConfig() returned empty bundle", bundle.isEmpty());
+ assertWithMessage("CarrierConfigManager#getConfig() returned null")
+ .that(bundle)
+ .isNotNull();
+ assertWithMessage("CarrierConfigManager#getConfig() returned empty bundle")
+ .that(bundle.isEmpty())
+ .isFalse();
int subId = SubscriptionManager.getDefaultSubscriptionId();
bundle = mCarrierConfigManager.getConfigForSubId(subId);
- assertNotNull("CarrierConfigManager#getConfigForSubId() returned null", bundle);
- assertFalse("CarrierConfigManager#getConfigForSubId() returned empty bundle",
- bundle.isEmpty());
+ assertWithMessage("CarrierConfigManager#getConfigForSubId() returned null")
+ .that(bundle)
+ .isNotNull();
+ assertWithMessage("CarrierConfigManager#getConfigForSubId() returned empty bundle")
+ .that(bundle.isEmpty())
+ .isFalse();
} catch (SecurityException e) {
- failMessage();
+ fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
}
}
+ @Test
public void testTelephonyApisAreAccessible() {
- if (!hasCellular) return;
// The following methods may return any value depending on the state of the device. Simply
// call them to make sure they do not throw any exceptions. Methods that return a device
// identifier will be accessible to apps with carrier privileges in Q, but this may change
@@ -507,54 +521,65 @@
mTelephonyManager.getManualNetworkSelectionPlmn();
mTelephonyManager.setForbiddenPlmns(new ArrayList<String>());
} catch (SecurityException e) {
- failMessage();
+ fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
}
}
+ @Test
public void testVoicemailTableIsAccessible() throws Exception {
- if (!hasCellular) return;
ContentValues value = new ContentValues();
value.put(VoicemailContract.Voicemails.NUMBER, "0123456789");
value.put(VoicemailContract.Voicemails.SOURCE_PACKAGE, selfPackageName);
try {
Uri uri = mVoicemailProvider.insert(mVoicemailContentUri, value);
- assertNotNull(uri);
- Cursor cursor = mVoicemailProvider.query(uri,
- new String[] {
- VoicemailContract.Voicemails.NUMBER,
- VoicemailContract.Voicemails.SOURCE_PACKAGE
- }, null, null, null);
- assertNotNull(cursor);
- assertTrue(cursor.moveToFirst());
- assertEquals("0123456789", cursor.getString(0));
- assertEquals(selfPackageName, cursor.getString(1));
- assertFalse(cursor.moveToNext());
+ assertThat(uri).isNotNull();
+ Cursor cursor =
+ mVoicemailProvider.query(
+ uri,
+ new String[] {
+ VoicemailContract.Voicemails.NUMBER,
+ VoicemailContract.Voicemails.SOURCE_PACKAGE
+ },
+ null,
+ null,
+ null);
+ assertThat(cursor).isNotNull();
+ assertThat(cursor.moveToFirst()).isTrue();
+ assertThat(cursor.getString(0)).isEqualTo("0123456789");
+ assertThat(cursor.getString(1)).isEqualTo(selfPackageName);
+ assertThat(cursor.moveToNext()).isFalse();
} catch (SecurityException e) {
- failMessage();
+ fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
}
}
+ @Test
public void testVoicemailStatusTableIsAccessible() throws Exception {
- if (!hasCellular) return;
ContentValues value = new ContentValues();
- value.put(VoicemailContract.Status.CONFIGURATION_STATE,
+ value.put(
+ VoicemailContract.Status.CONFIGURATION_STATE,
VoicemailContract.Status.CONFIGURATION_STATE_OK);
value.put(VoicemailContract.Status.SOURCE_PACKAGE, selfPackageName);
try {
Uri uri = mStatusProvider.insert(mStatusContentUri, value);
- assertNotNull(uri);
- Cursor cursor = mVoicemailProvider.query(uri,
- new String[] {
- VoicemailContract.Status.CONFIGURATION_STATE,
- VoicemailContract.Status.SOURCE_PACKAGE
- }, null, null, null);
- assertNotNull(cursor);
- assertTrue(cursor.moveToFirst());
- assertEquals(VoicemailContract.Status.CONFIGURATION_STATE_OK, cursor.getInt(0));
- assertEquals(selfPackageName, cursor.getString(1));
- assertFalse(cursor.moveToNext());
+ assertThat(uri).isNotNull();
+ Cursor cursor =
+ mVoicemailProvider.query(
+ uri,
+ new String[] {
+ VoicemailContract.Status.CONFIGURATION_STATE,
+ VoicemailContract.Status.SOURCE_PACKAGE
+ },
+ null,
+ null,
+ null);
+ assertThat(cursor).isNotNull();
+ assertThat(cursor.moveToFirst()).isTrue();
+ assertThat(cursor.getInt(0)).isEqualTo(VoicemailContract.Status.CONFIGURATION_STATE_OK);
+ assertThat(cursor.getString(1)).isEqualTo(selfPackageName);
+ assertThat(cursor.moveToNext()).isFalse();
} catch (SecurityException e) {
- failMessage();
+ fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
}
}
@@ -573,23 +598,23 @@
static final int CARRIER_PRIVILEGE_LISTENERS =
READ_PHONE_STATE_LISTENERS | READ_PRECISE_PHONE_STATE_LISTENERS;
+ @Test
public void testGetManualNetworkSelectionPlmnPersisted() throws Exception {
- if (!hasCellular) return;
if (mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_GSM) return;
try {
mTelephonyManager.setNetworkSelectionModeManual(
- TESTING_PLMN/* operatorNumeric */, true /* persistSelection */);
+ TESTING_PLMN /* operatorNumeric */, true /* persistSelection */);
String plmn = mTelephonyManager.getManualNetworkSelectionPlmn();
- assertEquals(TESTING_PLMN, plmn);
+ assertThat(plmn).isEqualTo(TESTING_PLMN);
} finally {
mTelephonyManager.setNetworkSelectionModeAutomatic();
}
}
+ @Test
public void testPhoneStateListener() throws Exception {
- if (!hasCellular) return;
- PhoneStateListener psl = new PhoneStateListener((Runnable r) -> { });
+ PhoneStateListener psl = new PhoneStateListener((Runnable r) -> {});
try {
mTelephonyManager.listen(psl, CARRIER_PRIVILEGE_LISTENERS);
} finally {
@@ -597,60 +622,59 @@
}
}
+ @Test
public void testIsManualNetworkSelectionAllowed() throws Exception {
- if (!hasCellular) return;
if (mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_GSM) return;
try {
- assertTrue(mTelephonyManager.isManualNetworkSelectionAllowed());
+ assertThat(mTelephonyManager.isManualNetworkSelectionAllowed()).isTrue();
} catch (SecurityException e) {
- failMessage();
+ fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
}
}
+ @Test
public void testGetNetworkSelectionMode() throws Exception {
- if (!hasCellular) return;
-
try {
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
- (tm) -> tm.setNetworkSelectionModeAutomatic());
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+ mTelephonyManager, (tm) -> tm.setNetworkSelectionModeAutomatic());
int networkMode = mTelephonyManager.getNetworkSelectionMode();
- assertEquals(TelephonyManager.NETWORK_SELECTION_MODE_AUTO, networkMode);
+ assertThat(networkMode).isEqualTo(TelephonyManager.NETWORK_SELECTION_MODE_AUTO);
} catch (SecurityException e) {
- failMessage();
+ fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
}
}
+ @Test
public void testSubscriptionInfoChangeListener() throws Exception {
- if (!hasCellular) return;
final AtomicReference<SecurityException> error = new AtomicReference<>();
final CountDownLatch latch = new CountDownLatch(1);
- new Handler(mListenerThread.getLooper()).post(() -> {
- SubscriptionManager.OnSubscriptionsChangedListener listener =
- new SubscriptionManager.OnSubscriptionsChangedListener();
- try {
- mSubscriptionManager.addOnSubscriptionsChangedListener(listener);
- } catch (SecurityException e) {
- error.set(e);
- } finally {
- mSubscriptionManager.removeOnSubscriptionsChangedListener(listener);
- latch.countDown();
- }
- });
- assertTrue("Test timed out", latch.await(30L, TimeUnit.SECONDS));
+ new Handler(mListenerThread.getLooper())
+ .post(
+ () -> {
+ SubscriptionManager.OnSubscriptionsChangedListener listener =
+ new SubscriptionManager.OnSubscriptionsChangedListener();
+ try {
+ mSubscriptionManager.addOnSubscriptionsChangedListener(listener);
+ } catch (SecurityException e) {
+ error.set(e);
+ } finally {
+ mSubscriptionManager.removeOnSubscriptionsChangedListener(listener);
+ latch.countDown();
+ }
+ });
+ assertWithMessage("Test timed out").that(latch.await(30L, TimeUnit.SECONDS)).isTrue();
if (error.get() != null) {
- failMessage();
+ fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
}
-
}
/**
* Test that it's possible to open logical channels to the ICC. This mirrors the Manage Channel
* command described in TS 102 221 Section 11.1.17.
*/
+ @Test
public void testIccOpenLogicalChannel() {
- if (!hasCellular) return;
-
// The AID here doesn't matter - we just need to open a valid connection. In this case, the
// specified AID ("") opens a channel and selects the MF.
IccOpenLogicalChannelResponse response = mTelephonyManager.iccOpenLogicalChannel("");
@@ -662,9 +686,8 @@
}
}
+ @Test
public void testIccOpenLogicalChannelWithValidP2() {
- if (!hasCellular) return;
-
// {@link TelephonyManager#iccOpenLogicalChannel} sends a Manage Channel (open) APDU
// followed by a Select APDU with the given AID and p2 values. See Open Mobile API
// Specification v3.2 Section 6.2.7.h and TS 102 221 for details.
@@ -678,9 +701,8 @@
}
}
+ @Test
public void testIccOpenLogicalChannelWithInvalidP2() {
- if (!hasCellular) return;
-
// Valid p2 values are defined in TS 102 221 Table 11.2. Per Table 11.2, 0xF0 should be
// invalid. Any p2 values that produce non '9000'/'62xx'/'63xx' status words are treated as
// an error and the channel is not opened. Due to compatibility issues with older devices,
@@ -690,8 +712,8 @@
IccOpenLogicalChannelResponse response =
mTelephonyManager.iccOpenLogicalChannel("", p2);
final int logicalChannel = response.getChannel();
- assertEquals(INVALID_CHANNEL, logicalChannel);
- assertNotEquals(STATUS_NO_ERROR, response.getStatus());
+ assertThat(logicalChannel).isEqualTo(INVALID_CHANNEL);
+ assertThat(response.getStatus()).isNotEqualTo(STATUS_NO_ERROR);
}
}
@@ -699,36 +721,32 @@
* Test that it's possible to close logical channels to the ICC. This follows the Manage Channel
* command described in TS 102 221 Section 11.1.17.
*/
+ @Test
public void testIccCloseLogicalChannel() {
- if (!hasCellular) return;
-
// The directory here doesn't matter - we just need to open a valid connection that can
// later be closed. In this case, the specified AID ("") opens a channel and selects the MF.
IccOpenLogicalChannelResponse response = mTelephonyManager.iccOpenLogicalChannel("");
// Check that the select command succeeded. This ensures that the logical channel is indeed
// open.
- assertArrayEquals(STATUS_NORMAL, response.getSelectResponse());
- assertTrue(mTelephonyManager.iccCloseLogicalChannel(response.getChannel()));
+ assertThat(response.getSelectResponse()).isEqualTo(STATUS_NORMAL);
+ assertThat(mTelephonyManager.iccCloseLogicalChannel(response.getChannel())).isTrue();
// Close opened channel twice.
- assertFalse(mTelephonyManager.iccCloseLogicalChannel(response.getChannel()));
+ assertThat(mTelephonyManager.iccCloseLogicalChannel(response.getChannel())).isFalse();
// Channel 0 is guaranteed to be always available and cannot be closed, per TS 102 221
// Section 11.1.17
- assertFalse(mTelephonyManager.iccCloseLogicalChannel(0));
+ assertThat(mTelephonyManager.iccCloseLogicalChannel(0)).isFalse();
}
/**
* This test ensures that valid APDU instructions can be sent and processed by the ICC. To do
- * so, APDUs are sent to:
- * - get the status of the MF
- * - select the Access Rule Reference (ARR) for the MF
- * - get the FCP template response for the select
+ * so, APDUs are sent to: - get the status of the MF - select the Access Rule Reference (ARR)
+ * for the MF - get the FCP template response for the select
*/
+ @Test
public void testIccTransmitApduLogicalChannel() {
- if (!hasCellular) return;
-
// An open LC is required for transmitting APDU commands. This opens an LC to the MF.
IccOpenLogicalChannelResponse iccOpenLogicalChannelResponse =
mTelephonyManager.iccOpenLogicalChannel("");
@@ -741,7 +759,7 @@
int cla = CLA_STATUS;
int p1 = 0; // no indication of application status
int p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel()
- // above
+ // above
int p3 = 0; // length of 'data' payload
String data = "";
String response =
@@ -749,8 +767,8 @@
logicalChannel, cla, COMMAND_STATUS, p1, p2, p3, data);
FcpTemplate fcpTemplate = FcpTemplate.parseFcpTemplate(response);
// Check that the FCP Template's file ID matches the MF
- assertTrue(containsFileId(fcpTemplate, MF_FILE_ID));
- assertEquals(STATUS_NORMAL_STRING, fcpTemplate.getStatus());
+ assertThat(containsFileId(fcpTemplate, MF_FILE_ID)).isTrue();
+ assertThat(fcpTemplate.getStatus()).isEqualTo(STATUS_NORMAL_STRING);
// Select the Access Rule Reference for the MF. Similar to the MF, this will exist
// across all SIM cards. TS 102 221 Section 11.1.1
@@ -785,8 +803,8 @@
fcpTemplate = FcpTemplate.parseFcpTemplate(response);
// Check that the FCP Template's file ID matches the selected ARR
- assertTrue(containsFileId(fcpTemplate, MF_ARR_FILE_ID));
- assertEquals(STATUS_NORMAL_STRING, fcpTemplate.getStatus());
+ assertThat(containsFileId(fcpTemplate, MF_ARR_FILE_ID)).isTrue();
+ assertThat(fcpTemplate.getStatus()).isEqualTo(STATUS_NORMAL_STRING);
} finally {
mTelephonyManager.iccCloseLogicalChannel(logicalChannel);
}
@@ -796,9 +814,8 @@
* Tests several invalid APDU instructions over a logical channel and makes sure appropriate
* errors are returned from the UICC.
*/
+ @Test
public void testIccTransmitApduLogicalChannelWithInvalidInputs() {
- if (!hasCellular) return;
-
// An open LC is required for transmitting apdu commands. This opens an LC to the MF.
IccOpenLogicalChannelResponse iccOpenLogicalChannelResponse =
mTelephonyManager.iccOpenLogicalChannel("");
@@ -810,13 +827,13 @@
int cla = CLA_STATUS | logicalChannel;
int p1 = 0xFF; // only '00', '01', and '02' are allowed
int p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel()
- // above
+ // above
int p3 = 0; // length of 'data' payload
String data = "";
String response =
mTelephonyManager.iccTransmitApduLogicalChannel(
logicalChannel, cla, COMMAND_STATUS, p1, p2, p3, data);
- assertTrue(INVALID_PARAMETERS_STATUSES.contains(response));
+ assertThat(INVALID_PARAMETERS_STATUSES.contains(response)).isTrue();
// Select a file that doesn't exist
cla = CLA_SELECT;
@@ -827,7 +844,7 @@
response =
mTelephonyManager.iccTransmitApduLogicalChannel(
logicalChannel, cla, COMMAND_SELECT, p1, p2, p3, data);
- assertEquals(STATUS_FILE_NOT_FOUND, response);
+ assertThat(response).isEqualTo(STATUS_FILE_NOT_FOUND);
// Manage channel with incorrect p1 parameter
cla = CLA_MANAGE_CHANNEL | logicalChannel;
@@ -838,7 +855,7 @@
response =
mTelephonyManager.iccTransmitApduLogicalChannel(
logicalChannel, cla, COMMAND_MANAGE_CHANNEL, p1, p2, p3, data);
- assertTrue(isErrorResponse(response));
+ assertThat(isErrorResponse(response)).isTrue();
// Use an incorrect class byte for Status apdu
cla = 0xFF;
@@ -849,7 +866,7 @@
response =
mTelephonyManager.iccTransmitApduLogicalChannel(
logicalChannel, cla, COMMAND_STATUS, p1, p2, p3, data);
- assertEquals(STATUS_WRONG_CLASS, response);
+ assertThat(response).isEqualTo(STATUS_WRONG_CLASS);
// Provide a data field that is longer than described for Select apdu
cla = CLA_SELECT | logicalChannel;
@@ -860,7 +877,7 @@
response =
mTelephonyManager.iccTransmitApduLogicalChannel(
logicalChannel, cla, COMMAND_SELECT, p1, p2, p3, data);
- assertTrue(isErrorResponse(response));
+ assertThat(isErrorResponse(response)).isTrue();
// Use an invalid instruction
cla = 0;
@@ -872,7 +889,7 @@
response =
mTelephonyManager.iccTransmitApduLogicalChannel(
logicalChannel, cla, invalidInstruction, p1, p2, p3, data);
- assertTrue(isErrorResponse(response));
+ assertThat(isErrorResponse(response)).isTrue();
} finally {
mTelephonyManager.iccCloseLogicalChannel(logicalChannel);
}
@@ -882,9 +899,8 @@
* This test ensures that files can be read off the UICC. This helps to test the SIM booting
* process, as it process involves several file-reads. The ICCID is one of the first files read.
*/
+ @Test
public void testApduFileRead() {
- if (!hasCellular) return;
-
// Open a logical channel and select the MF.
IccOpenLogicalChannelResponse iccOpenLogicalChannel =
mTelephonyManager.iccOpenLogicalChannel("");
@@ -898,7 +914,7 @@
String response =
mTelephonyManager.iccTransmitApduLogicalChannel(
logicalChannel, CLA_SELECT, COMMAND_SELECT, p1, p2, p3, ICCID_FILE_ID);
- assertEquals(STATUS_NORMAL_STRING, response);
+ assertThat(response).isEqualTo(STATUS_NORMAL_STRING);
// Read the contents of the ICCID.
p1 = 0; // 0-byte offset
@@ -907,27 +923,25 @@
response =
mTelephonyManager.iccTransmitApduLogicalChannel(
logicalChannel, CLA_READ_BINARY, COMMAND_READ_BINARY, p1, p2, p3, "");
- assertTrue(response.endsWith(STATUS_NORMAL_STRING));
+ assertThat(response).endsWith(STATUS_NORMAL_STRING);
} finally {
mTelephonyManager.iccCloseLogicalChannel(logicalChannel);
}
}
- /**
- * This test sends several valid APDU commands over the basic channel (channel 0).
- */
+ /** This test sends several valid APDU commands over the basic channel (channel 0). */
+ @Test
public void testIccTransmitApduBasicChannel() {
- if (!hasCellular) return;
-
// select the MF
int cla = CLA_SELECT;
int p1 = 0; // select EF by FID
int p2 = 0x0C; // requesting FCP template
int p3 = 2; // length of 'data' payload
String data = MF_FILE_ID;
- String response = mTelephonyManager
- .iccTransmitApduBasicChannel(cla, COMMAND_SELECT, p1, p2, p3, data);
- assertEquals(STATUS_NORMAL_STRING, response);
+ String response =
+ mTelephonyManager.iccTransmitApduBasicChannel(
+ cla, COMMAND_SELECT, p1, p2, p3, data);
+ assertThat(response).isEqualTo(STATUS_NORMAL_STRING);
// get the Status of the current file/directory
cla = CLA_STATUS;
@@ -935,10 +949,11 @@
p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel() above
p3 = 0; // length of 'data' payload
data = "";
- response = mTelephonyManager
- .iccTransmitApduBasicChannel(cla, COMMAND_STATUS, p1, p2, p3, data);
+ response =
+ mTelephonyManager.iccTransmitApduBasicChannel(
+ cla, COMMAND_STATUS, p1, p2, p3, data);
FcpTemplate fcpTemplate = FcpTemplate.parseFcpTemplate(response);
- assertTrue(containsFileId(fcpTemplate, MF_FILE_ID));
+ assertThat(containsFileId(fcpTemplate, MF_FILE_ID)).isTrue();
// Manually open a logical channel
cla = CLA_MANAGE_CHANNEL;
@@ -946,11 +961,12 @@
p2 = 0; // '00' for open command
p3 = 0; // length of data payload
data = "";
- response = mTelephonyManager
- .iccTransmitApduBasicChannel(cla, COMMAND_MANAGE_CHANNEL, p1, p2, p3, data);
+ response =
+ mTelephonyManager.iccTransmitApduBasicChannel(
+ cla, COMMAND_MANAGE_CHANNEL, p1, p2, p3, data);
// response is in the format | 1 byte: channel number | 2 bytes: status word |
String responseStatus = response.substring(2);
- assertEquals(STATUS_NORMAL_STRING, responseStatus);
+ assertThat(responseStatus).isEqualTo(STATUS_NORMAL_STRING);
// Close the open channel
byte[] responseBytes = hexStringToBytes(response);
@@ -960,18 +976,18 @@
p2 = channel; // the channel to be closed
p3 = 0; // length of data payload
data = "";
- response = mTelephonyManager
- .iccTransmitApduBasicChannel(cla, COMMAND_MANAGE_CHANNEL, p1, p2, p3, data);
- assertEquals(STATUS_NORMAL_STRING, response);
+ response =
+ mTelephonyManager.iccTransmitApduBasicChannel(
+ cla, COMMAND_MANAGE_CHANNEL, p1, p2, p3, data);
+ assertThat(response).isEqualTo(STATUS_NORMAL_STRING);
}
/**
* This test verifies that {@link TelephonyManager#setLine1NumberForDisplay(String, String)}
* correctly sets the Line 1 alpha tag and number when called.
*/
+ @Test
public void testLine1NumberForDisplay() {
- if (!hasCellular) return;
-
// Cache original alpha tag and number values.
String originalAlphaTag = mTelephonyManager.getLine1AlphaTag();
String originalNumber = mTelephonyManager.getLine1Number();
@@ -982,18 +998,18 @@
String defaultAlphaTag = mTelephonyManager.getLine1AlphaTag();
String defaultNumber = mTelephonyManager.getLine1Number();
- assertTrue(mTelephonyManager.setLine1NumberForDisplay(ALPHA_TAG_A, NUMBER_A));
- assertEquals(ALPHA_TAG_A, mTelephonyManager.getLine1AlphaTag());
- assertEquals(NUMBER_A, mTelephonyManager.getLine1Number());
+ assertThat(mTelephonyManager.setLine1NumberForDisplay(ALPHA_TAG_A, NUMBER_A)).isTrue();
+ assertThat(mTelephonyManager.getLine1AlphaTag()).isEqualTo(ALPHA_TAG_A);
+ assertThat(mTelephonyManager.getLine1Number()).isEqualTo(NUMBER_A);
- assertTrue(mTelephonyManager.setLine1NumberForDisplay(ALPHA_TAG_B, NUMBER_B));
- assertEquals(ALPHA_TAG_B, mTelephonyManager.getLine1AlphaTag());
- assertEquals(NUMBER_B, mTelephonyManager.getLine1Number());
+ assertThat(mTelephonyManager.setLine1NumberForDisplay(ALPHA_TAG_B, NUMBER_B)).isTrue();
+ assertThat(mTelephonyManager.getLine1AlphaTag()).isEqualTo(ALPHA_TAG_B);
+ assertThat(mTelephonyManager.getLine1Number()).isEqualTo(NUMBER_B);
// null is used to clear the Line 1 alpha tag and number values.
- assertTrue(mTelephonyManager.setLine1NumberForDisplay(null, null));
- assertEquals(defaultAlphaTag, mTelephonyManager.getLine1AlphaTag());
- assertEquals(defaultNumber, mTelephonyManager.getLine1Number());
+ assertThat(mTelephonyManager.setLine1NumberForDisplay(null, null)).isTrue();
+ assertThat(mTelephonyManager.getLine1AlphaTag()).isEqualTo(defaultAlphaTag);
+ assertThat(mTelephonyManager.getLine1Number()).isEqualTo(defaultNumber);
} finally {
// Reset original alpha tag and number values.
mTelephonyManager.setLine1NumberForDisplay(originalAlphaTag, originalNumber);
@@ -1004,21 +1020,20 @@
* This test verifies that {@link TelephonyManager#setVoiceMailNumber(String, String)} correctly
* sets the VoiceMail alpha tag and number when called.
*/
+ @Test
public void testVoiceMailNumber() {
- if (!hasCellular) return;
-
// Cache original alpha tag and number values.
String originalAlphaTag = mTelephonyManager.getVoiceMailAlphaTag();
String originalNumber = mTelephonyManager.getVoiceMailNumber();
try {
- assertTrue(mTelephonyManager.setVoiceMailNumber(ALPHA_TAG_A, NUMBER_A));
- assertEquals(ALPHA_TAG_A, mTelephonyManager.getVoiceMailAlphaTag());
- assertEquals(NUMBER_A, mTelephonyManager.getVoiceMailNumber());
+ assertThat(mTelephonyManager.setVoiceMailNumber(ALPHA_TAG_A, NUMBER_A)).isTrue();
+ assertThat(mTelephonyManager.getVoiceMailAlphaTag()).isEqualTo(ALPHA_TAG_A);
+ assertThat(mTelephonyManager.getVoiceMailNumber()).isEqualTo(NUMBER_A);
- assertTrue(mTelephonyManager.setVoiceMailNumber(ALPHA_TAG_B, NUMBER_B));
- assertEquals(ALPHA_TAG_B, mTelephonyManager.getVoiceMailAlphaTag());
- assertEquals(NUMBER_B, mTelephonyManager.getVoiceMailNumber());
+ assertThat(mTelephonyManager.setVoiceMailNumber(ALPHA_TAG_B, NUMBER_B)).isTrue();
+ assertThat(mTelephonyManager.getVoiceMailAlphaTag()).isEqualTo(ALPHA_TAG_B);
+ assertThat(mTelephonyManager.getVoiceMailNumber()).isEqualTo(NUMBER_B);
} finally {
// Reset original alpha tag and number values.
mTelephonyManager.setVoiceMailNumber(originalAlphaTag, originalNumber);
@@ -1029,12 +1044,11 @@
* This test verifies that {@link SubscriptionManager#createSubscriptionGroup(List)} correctly
* create a group with the given subscription id.
*
- * This also verifies that
- * {@link SubscriptionManager#removeSubscriptionsFromGroup(List, ParcelUuid)} correctly remove
- * the given subscription group.
+ * <p>This also verifies that {@link SubscriptionManager#removeSubscriptionsFromGroup(List,
+ * ParcelUuid)} correctly remove the given subscription group.
*/
+ @Test
public void testCreateAndRemoveSubscriptionGroup() {
- if (!hasCellular) return;
// Set subscription group with current sub Id.
int subId = SubscriptionManager.getDefaultSubscriptionId();
List<Integer> subGroup = Arrays.asList(subId);
@@ -1044,19 +1058,20 @@
List<SubscriptionInfo> infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid);
try {
- assertEquals(1, infoList.size());
- assertEquals(uuid, infoList.get(0).getGroupUuid());
- assertEquals(subId, infoList.get(0).getSubscriptionId());
+ assertThat(infoList).hasSize(1);
+ assertThat(infoList.get(0).getGroupUuid()).isEqualTo(uuid);
+ assertThat(infoList.get(0).getSubscriptionId()).isEqualTo(subId);
} finally {
// Verify that the given subGroup has been removed.
mSubscriptionManager.removeSubscriptionsFromGroup(subGroup, uuid);
infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid);
- assertTrue(infoList.isEmpty());
+ assertThat(infoList).isEmpty();
}
}
+ @Test
public void testAddSubscriptionToExistingGroupForMultipleSims() {
- if (!hasCellular || mTelephonyManager.getPhoneCount() < DSDS_PHONE_COUNT) return;
+ if (mTelephonyManager.getPhoneCount() < DSDS_PHONE_COUNT) return;
// Set subscription group with current sub Id.
int subId = SubscriptionManager.getDefaultDataSubscriptionId();
@@ -1069,7 +1084,7 @@
mSubscriptionManager.getActiveSubscriptionInfoList();
// Verify that the device has at least two active subscriptions.
- assertTrue(activeSubInfos.size() >= DSDS_PHONE_COUNT);
+ assertThat(activeSubInfos.size()).isAtLeast(DSDS_PHONE_COUNT);
List<Integer> activeSubGroup = getSubscriptionIdList(activeSubInfos);
activeSubGroup.removeIf(id -> id == subId);
@@ -1079,23 +1094,21 @@
List<Integer> infoList =
getSubscriptionIdList(mSubscriptionManager.getSubscriptionsInGroup(uuid));
activeSubGroup.add(subId);
- assertEquals(activeSubGroup.size(), infoList.size());
- assertTrue(activeSubGroup.containsAll(infoList));
+ assertThat(infoList).hasSize(activeSubGroup.size());
+ assertThat(infoList).containsExactly(activeSubGroup);
} finally {
removeSubscriptionsFromGroup(uuid);
}
}
/**
- * This test verifies that
- * {@link SubscriptionManager#addSubscriptionsIntoGroup(List, ParcelUuid)}} correctly add some
- * additional subscriptions to the existing group.
+ * This test verifies that {@link SubscriptionManager#addSubscriptionsIntoGroup(List,
+ * ParcelUuid)}} correctly add some additional subscriptions to the existing group.
*
- * This test required the device has more than one subscription.
+ * <p>This test required the device has more than one subscription.
*/
+ @Test
public void testAddSubscriptionToExistingGroupForEsim() {
- if (!hasCellular) return;
-
// Set subscription group with current sub Id.
int subId = SubscriptionManager.getDefaultDataSubscriptionId();
if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return;
@@ -1114,8 +1127,8 @@
List<Integer> infoList =
getSubscriptionIdList(mSubscriptionManager.getSubscriptionsInGroup(uuid));
accessibleSubGroup.add(subId);
- assertEquals(accessibleSubGroup.size(), infoList.size());
- assertTrue(accessibleSubGroup.containsAll(infoList));
+ assertThat(infoList).hasSize(accessibleSubGroup.size());
+ assertThat(infoList).containsExactly(accessibleSubGroup);
}
} finally {
removeSubscriptionsFromGroup(uuid);
@@ -1126,9 +1139,8 @@
* This test verifies that {@link SubscriptionManager#setOpportunistic(boolean, int)} correctly
* set the opportunistic property of the given subscription.
*/
+ @Test
public void testOpportunistic() {
- if (!hasCellular) return;
-
int subId = SubscriptionManager.getDefaultDataSubscriptionId();
if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return;
SubscriptionInfo info = mSubscriptionManager.getActiveSubscriptionInfo(subId);
@@ -1137,17 +1149,16 @@
try {
// Mark the given subscription as opportunistic subscription.
- boolean successed = mSubscriptionManager.setOpportunistic(newOpportunistic, subId);
- assertTrue(successed);
+ assertThat(mSubscriptionManager.setOpportunistic(newOpportunistic, subId)).isTrue();
// Verify that the given subscription is opportunistic subscription.
info = mSubscriptionManager.getActiveSubscriptionInfo(subId);
- assertEquals(newOpportunistic, info.isOpportunistic());
+ assertThat(info.isOpportunistic()).isEqualTo(newOpportunistic);
} finally {
// Set back to original opportunistic property.
mSubscriptionManager.setOpportunistic(oldOpportunistic, subId);
info = mSubscriptionManager.getActiveSubscriptionInfo(subId);
- assertEquals(oldOpportunistic, info.isOpportunistic());
+ assertThat(info.isOpportunistic()).isEqualTo(oldOpportunistic);
}
}
@@ -1156,9 +1167,8 @@
* String)} correctly transmits iccIO commands to the UICC card. First, the MF is selected via a
* SELECT apdu via the basic channel, then a STATUS AT-command is sent.
*/
+ @Test
public void testIccExchangeSimIO() {
- if (!hasCellular) return;
-
// select the MF first. This makes sure the next STATUS AT-command returns a FCP template
// for the right file.
int cla = CLA_SELECT;
@@ -1166,65 +1176,71 @@
int p2 = 0x0C; // requesting FCP template
int p3 = 2; // length of 'data' payload
String data = MF_FILE_ID;
- String response = mTelephonyManager
- .iccTransmitApduBasicChannel(cla, COMMAND_SELECT, p1, p2, p3, data);
- assertEquals(STATUS_NORMAL_STRING, response);
+ String response =
+ mTelephonyManager.iccTransmitApduBasicChannel(
+ cla, COMMAND_SELECT, p1, p2, p3, data);
+ assertThat(response).isEqualTo(STATUS_NORMAL_STRING);
// The iccExchangeSimIO command implements the +CRSM command defined in TS 27.007 section
// 8.18. A STATUS command is sent and the returned value will be an FCP template.
- byte[] result = mTelephonyManager.iccExchangeSimIO(
- 0, // fileId: not required for STATUS
- COMMAND_STATUS, // command: STATUS
- 0, // p1: not required for STATUS
- 0, // p2: not required for STATUS
- 0, // p3: not required for STATUS
- ""); // filePath: not required for STATUS
+ byte[] result =
+ mTelephonyManager.iccExchangeSimIO(
+ 0, // fileId: not required for STATUS
+ COMMAND_STATUS, // command: STATUS
+ 0, // p1: not required for STATUS
+ 0, // p2: not required for STATUS
+ 0, // p3: not required for STATUS
+ ""); // filePath: not required for STATUS
String resultString = bytesToHexString(result);
FcpTemplate fcpTemplate = FcpTemplate.parseFcpTemplate(resultString);
- assertTrue(containsFileId(fcpTemplate, MF_FILE_ID));
- assertEquals("iccExchangeSimIO returned non-normal Status byte: " + resultString,
- STATUS_NORMAL_STRING, fcpTemplate.getStatus());
+ assertThat(containsFileId(fcpTemplate, MF_FILE_ID)).isTrue();
+ assertWithMessage("iccExchangeSimIO returned non-normal Status byte: %s", resultString)
+ .that(fcpTemplate.getStatus())
+ .isEqualTo(STATUS_NORMAL_STRING);
}
/**
* This test checks that a STATUS apdu can be sent as an encapsulated envelope to the UICC via
* {@link TelephonyManager#sendEnvelopeWithStatus(String)}.
*/
+ @Test
public void testSendEnvelopeWithStatus() {
- if (!hasCellular) return;
-
// STATUS apdu as hex String
String envelope =
CLA_STATUS_STRING
- + COMMAND_STATUS_STRING
- + "00" // p1: no indication of application status
- + "00"; // p2: identical parameters to
+ + COMMAND_STATUS_STRING
+ + "00" // p1: no indication of application status
+ + "00"; // p2: identical parameters to
String response = mTelephonyManager.sendEnvelopeWithStatus(envelope);
// TODO(b/137963715): add more specific assertions on response from TelMan#sendEnvelope
- assertNotNull("sendEnvelopeWithStatus is null for envelope=" + envelope, response);
+ assertWithMessage("sendEnvelopeWithStatus is null for envelope=%s", envelope)
+ .that(response)
+ .isNotNull();
}
/**
* This test checks that applications with carrier privilege can set/clear signal strength
- * update request via
- * {@link TelephonyManager#setSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)} and
- * {@link TelephonyManager#clearSignalStrengthUpdateRequest} without
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+ * update request via {@link
+ * TelephonyManager#setSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)} and {@link
+ * TelephonyManager#clearSignalStrengthUpdateRequest} without {@link
+ * android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
*/
+ @Test
public void testSetClearSignalStrengthUpdateRequest() {
- if (!hasCellular) return;
-
final SignalStrengthUpdateRequest request =
new SignalStrengthUpdateRequest.Builder()
- .setSignalThresholdInfos(List.of(
- new SignalThresholdInfo.Builder()
- .setRadioAccessNetworkType(
- AccessNetworkConstants.AccessNetworkType.GERAN)
- .setSignalMeasurementType(
- SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI)
- .setThresholds(new int[]{-113, -103, -97, -51})
- .build()))
+ .setSignalThresholdInfos(
+ List.of(
+ new SignalThresholdInfo.Builder()
+ .setRadioAccessNetworkType(
+ AccessNetworkConstants.AccessNetworkType
+ .GERAN)
+ .setSignalMeasurementType(
+ SignalThresholdInfo
+ .SIGNAL_MEASUREMENT_TYPE_RSSI)
+ .setThresholds(new int[] {-113, -103, -97, -51})
+ .build()))
.setReportingRequestedWhileIdle(true)
.build();
try {
@@ -1237,20 +1253,19 @@
private void verifyValidIccOpenLogicalChannelResponse(IccOpenLogicalChannelResponse response) {
// The assigned channel should be between the min and max allowed channel numbers
int channel = response.getChannel();
- assertTrue(MIN_LOGICAL_CHANNEL <= channel && channel <= MAX_LOGICAL_CHANNEL);
- assertEquals(STATUS_NO_ERROR, response.getStatus());
- assertArrayEquals(STATUS_NORMAL, response.getSelectResponse());
+ assertThat(channel).isIn(Range.closed(MIN_LOGICAL_CHANNEL, MAX_LOGICAL_CHANNEL));
+ assertThat(response.getStatus()).isEqualTo(STATUS_NO_ERROR);
+ assertThat(response.getSelectResponse()).isEqualTo(STATUS_NORMAL);
}
private void removeSubscriptionsFromGroup(ParcelUuid uuid) {
List<SubscriptionInfo> infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid);
if (!infoList.isEmpty()) {
mSubscriptionManager.removeSubscriptionsFromGroup(
- getSubscriptionIdList(infoList),
- uuid);
+ getSubscriptionIdList(infoList), uuid);
}
infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid);
- assertTrue(infoList.isEmpty());
+ assertThat(infoList).isEmpty();
}
private List<Integer> getSubscriptionIdList(List<SubscriptionInfo> subInfoList) {
@@ -1265,26 +1280,24 @@
*
* @param fcpTemplate The FCP Template to be checked.
* @param fileId The file ID that is being searched for
- *
* @return true iff fcpTemplate contains fileId.
*/
private boolean containsFileId(FcpTemplate fcpTemplate, String fileId) {
- return fcpTemplate.getTlvs().stream().anyMatch(tlv ->
- tlv.getTag() == FILE_IDENTIFIER && tlv.getValue().equals(fileId));
+ return fcpTemplate.getTlvs().stream()
+ .anyMatch(tlv -> tlv.getTag() == FILE_IDENTIFIER && tlv.getValue().equals(fileId));
}
/**
* Returns true iff {@code response} indicates an error with the previous APDU.
*
* @param response The APDU response to be checked.
- *
* @return true iff the given response indicates an error occurred
*/
private boolean isErrorResponse(@Nonnull String response) {
- return !(STATUS_NORMAL_STRING.equals(response) ||
- response.startsWith(STATUS_WARNING_A) ||
- response.startsWith(STATUS_WARNING_B) ||
- response.startsWith(STATUS_BYTES_REMAINING));
+ return !(STATUS_NORMAL_STRING.equals(response)
+ || response.startsWith(STATUS_WARNING_A)
+ || response.startsWith(STATUS_WARNING_B)
+ || response.startsWith(STATUS_BYTES_REMAINING));
}
private static class IntentReceiver extends BroadcastReceiver {
@@ -1300,8 +1313,11 @@
}
}
- @Suppress
+ @Test
public void testEapSimAuthentication() {
+ assumeTrue(
+ "testEapSimAuthentication requires a 2021 CTS UICC or newer",
+ UiccUtil.uiccHasCertificate(CTS_UICC_2021));
// K: '000102030405060708090A0B0C0D0E0F', defined by TS 134 108#8.2
// n: 128 (Bits to use for RES value)
// Format: [Length][RAND]
@@ -1313,14 +1329,16 @@
TelephonyManager.AUTHTYPE_EAP_SIM,
base64Challenge);
byte[] response = Base64.decode(base64Response, Base64.DEFAULT);
- assertArrayEquals(
- "Results for AUTHTYPE_EAP_SIM failed",
- hexStringToBytes(EXPECTED_EAP_SIM_RESULT),
- response);
+ assertWithMessage("Results for AUTHTYPE_EAP_SIM failed")
+ .that(response)
+ .isEqualTo(hexStringToBytes(EXPECTED_EAP_SIM_RESULT));
}
- @Suppress
+ @Test
public void testEapAkaAuthentication() {
+ assumeTrue(
+ "testEapAkaAuthentication requires a 2021 CTS UICC or newer",
+ UiccUtil.uiccHasCertificate(CTS_UICC_2021));
// K: '000102030405060708090A0B0C0D0E0F', defined by TS 134 108#8.2
// n: 128 (Bits to use for RES value)
// Format: [Length][Rand][Length][Autn]
@@ -1332,14 +1350,13 @@
TelephonyManager.AUTHTYPE_EAP_AKA,
base64Challenge);
- assertNotNull("UICC returned null for EAP-AKA auth", base64Response);
+ assertWithMessage("UICC returned null for EAP-AKA auth").that(base64Response).isNotNull();
byte[] response = Base64.decode(base64Response, Base64.NO_WRAP);
// response may be formatted as: [DB][Length][RES][Length][CK][Length][IK][Length][Kc]
byte[] akaResponse = Arrays.copyOfRange(response, 0, EAP_AKA_RESPONSE_LENGTH);
- assertArrayEquals(
- "Results for AUTHTYPE_EAP_AKA failed",
- hexStringToBytes(EXPECTED_EAP_AKA_RESULT),
- akaResponse);
+ assertWithMessage("Results for AUTHTYPE_EAP_AKA failed")
+ .that(akaResponse)
+ .isEqualTo(hexStringToBytes(EXPECTED_EAP_AKA_RESULT));
}
}
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/FcpTemplate.java b/tests/tests/carrierapi/src/android/carrierapi/cts/FcpTemplate.java
index a90c756..252b874 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/FcpTemplate.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/FcpTemplate.java
@@ -21,13 +21,14 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+
import javax.annotation.Nonnull;
/**
* Class for representing a File Control Parameters (FCP) Template object. TS 101 220
*
- * A correctly formatted FCP Template will be in the format:
- * | 1 byte: BER tag (0x62) | 1 byte: length of TLVs |...TLV objects...| 2 bytes: status |
+ * <p>A correctly formatted FCP Template will be in the format: | 1 byte: BER tag (0x62) | 1 byte:
+ * length of TLVs |...TLV objects...| 2 bytes: status |
*/
public class FcpTemplate {
@@ -69,12 +70,11 @@
* Parses and returns a FcpTemplate for the given {@code fcpResponse}
*
* @param fcpResponse The Hex String response for a given Status APDU command. Expected to be in
- * the format: | 1 byte: BER tag | 1 byte: length of TLVs |...TLV objects...| 2 bytes: status |
- *
+ * the format: | 1 byte: BER tag | 1 byte: length of TLVs |...TLV objects...| 2 bytes:
+ * status |
* @return a FcpTemplate for the given hex String
- *
* @throws FcpTemplateParseException for non-FCP inputs or inputs of the wrong length (encoded
- * length does not match actual length)
+ * length does not match actual length)
*/
public static FcpTemplate parseFcpTemplate(@Nonnull String fcpResponse) {
final List<Tlv> tlvObjects = new ArrayList<>();
@@ -98,17 +98,15 @@
int tag = data[index++] & 0xFF;
int length = data[index++] & 0xFF; // assumes that length is < 128 bytes.
String value = fcpResponse.substring(index * 2, (index + length) * 2);
- tlvObjects .add(new Tlv(tag, length, value));
+ tlvObjects.add(new Tlv(tag, length, value));
index += length;
}
String status = fcpResponse.substring(fcpResponse.length() - 4);
- return new FcpTemplate(tlvObjects , status);
+ return new FcpTemplate(tlvObjects, status);
}
- /**
- * Represents a Tag-Length-Value object. TS 101 220 Section 2
- */
+ /** Represents a Tag-Length-Value object. TS 101 220 Section 2 */
public static class Tlv {
private final int tag;
@@ -142,9 +140,7 @@
return false;
}
Tlv tlv = (Tlv) o;
- return tag == tlv.tag &&
- length == tlv.length &&
- value.equals(tlv.value);
+ return tag == tlv.tag && length == tlv.length && value.equals(tlv.value);
}
@Override
@@ -159,7 +155,6 @@
}
private static final class FcpTemplateParseException extends RuntimeException {
-
public FcpTemplateParseException(String message) {
super(message);
}
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/IccUtils.java b/tests/tests/carrierapi/src/android/carrierapi/cts/IccUtils.java
index 3409fe5..d36ca03 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/IccUtils.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/IccUtils.java
@@ -18,20 +18,18 @@
import javax.annotation.Nonnull;
-/**
- * Utility class for converting between hex Strings and bitwise representations.
- */
+/** Utility class for converting between hex Strings and bitwise representations. */
public class IccUtils {
// A table mapping from a number to a hex character for fast encoding hex strings.
private static final char[] HEX_CHARS = {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
@Nonnull
public static String bytesToHexString(byte[] bytes) {
StringBuilder ret = new StringBuilder(2 * bytes.length);
- for (int i = 0 ; i < bytes.length ; i++) {
+ for (int i = 0; i < bytes.length; i++) {
int b;
b = 0x0f & (bytes[i] >> 4);
ret.append(HEX_CHARS[b]);
@@ -44,11 +42,8 @@
/**
* Converts a hex String to a byte array.
*
- * @param s A string of hexadecimal characters, must be an even number of
- * chars long
- *
+ * @param s A string of hexadecimal characters, must be an even number of chars long
* @return byte array representation
- *
* @throws RuntimeException on invalid format
*/
public static byte[] hexStringToBytes(String s) {
@@ -58,10 +53,10 @@
int sz = s.length();
- ret = new byte[sz/2];
+ ret = new byte[sz / 2];
- for (int i=0 ; i <sz ; i+=2) {
- ret[i/2] = (byte) ((hexCharToInt(s.charAt(i)) << 4) | hexCharToInt(s.charAt(i+1)));
+ for (int i = 0; i < sz; i += 2) {
+ ret[i / 2] = (byte) ((hexCharToInt(s.charAt(i)) << 4) | hexCharToInt(s.charAt(i + 1)));
}
return ret;
@@ -71,12 +66,13 @@
* Converts a hex char to its integer value
*
* @param c A single hexadecimal character. Must be in one of these ranges:
- * - '0' to '9', or
- * - 'a' to 'f', or
- * - 'A' to 'F'
+ * <ul>
+ * <li>'0' to '9'
+ * <li>'a' to 'f'
+ * <li>'A' to 'F'
+ * </ul>
*
* @return the integer representation of {@code c}
- *
* @throws RuntimeException on invalid character
*/
public static int hexCharToInt(char c) {
@@ -84,6 +80,6 @@
if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
- throw new RuntimeException ("invalid hex char '" + c + "'");
+ throw new RuntimeException("invalid hex char '" + c + "'");
}
}
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
index 017d7fa..82655e9 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
@@ -18,13 +18,12 @@
import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
import static org.junit.Assert.fail;
-import android.content.Context;
+import android.content.ContentResolver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
@@ -64,15 +63,16 @@
import java.util.stream.Collectors;
/**
- * Build, install and run the tests by running the commands below:
- * make cts -j64
- * cts-tradefed run cts -m CtsCarrierApiTestCases --test android.carrierapi.cts.NetworkScanApiTest
+ * Unit tests for {@link TelephonyManager}'s network scan APIs.
+ *
+ * <p>Test using `atest CtsCarrierApiTestCases:NetworkScanApiTest` or `make cts -j64 && cts-tradefed
+ * run cts -m CtsCarrierApiTestCases --test android.carrierapi.cts.NetworkScanApiTest`
*/
@RunWith(AndroidJUnit4.class)
-public class NetworkScanApiTest {
- private TelephonyManager mTelephonyManager;
- private PackageManager mPackageManager;
+public class NetworkScanApiTest extends BaseCarrierApiTest {
private static final String TAG = "NetworkScanApiTest";
+
+ private TelephonyManager mTelephonyManager;
private int mNetworkScanStatus;
private static final int EVENT_NETWORK_SCAN_START = 100;
private static final int EVENT_NETWORK_SCAN_RESULTS = 200;
@@ -103,18 +103,18 @@
private static final int INCREMENTAL_RESULTS_PERIODICITY_SEC = 3;
private static final ArrayList<String> MCC_MNC = new ArrayList<>();
private static final RadioAccessSpecifier[] RADIO_ACCESS_SPECIFIERS = {
- new RadioAccessSpecifier(
- AccessNetworkConstants.AccessNetworkType.GERAN,
- null /* bands */,
- null /* channels */),
- new RadioAccessSpecifier(
- AccessNetworkConstants.AccessNetworkType.EUTRAN,
- null /* bands */,
- null /* channels */),
- new RadioAccessSpecifier(
- AccessNetworkConstants.AccessNetworkType.UTRAN,
- null /* bands */,
- null /* channels */)
+ new RadioAccessSpecifier(
+ AccessNetworkConstants.AccessNetworkType.GERAN,
+ null /* bands */,
+ null /* channels */),
+ new RadioAccessSpecifier(
+ AccessNetworkConstants.AccessNetworkType.EUTRAN,
+ null /* bands */,
+ null /* channels */),
+ new RadioAccessSpecifier(
+ AccessNetworkConstants.AccessNetworkType.UTRAN,
+ null /* bands */,
+ null /* channels */)
};
// Needed because NETWORK_SCAN_PERMISSION is a systemapi
@@ -122,20 +122,25 @@
@Before
public void setUp() throws Exception {
- Context context = InstrumentationRegistry.getContext();
- mTelephonyManager = (TelephonyManager)
- context.getSystemService(Context.TELEPHONY_SERVICE);
- mPackageManager = context.getPackageManager();
- InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
- context.getPackageName(), ACCESS_FINE_LOCATION);
- InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
- context.getPackageName(), ACCESS_BACKGROUND_LOCATION);
+ mTelephonyManager = getContext().getSystemService(TelephonyManager.class);
+ String selfPackageName = getContext().getPackageName();
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .grantRuntimePermission(selfPackageName, ACCESS_FINE_LOCATION);
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .grantRuntimePermission(selfPackageName, ACCESS_BACKGROUND_LOCATION);
mTestHandlerThread = new NetworkScanHandlerThread(TAG);
mTestHandlerThread.start();
}
@After
public void tearDown() throws Exception {
+ if (!werePreconditionsSatisfied()) return;
+
+ // Revoking runtime permissions makes ActivityManager kill our process, so we don't do it,
+ // as the test harness will eventually uninstall this APK after testing completes anyway, so
+ // we aren't really leaking anything long-term.
mTestHandlerThread.quit();
}
@@ -146,9 +151,7 @@
} catch (InterruptedException ie) {
}
- if (!mReady) {
- fail("NetworkScanApiTest failed to initialize");
- }
+ assertWithMessage("NetworkScanApiTest failed to initialize").that(mReady).isTrue();
}
}
@@ -168,41 +171,45 @@
@Override
public void onLooperPrepared() {
/* create a custom handler for the Handler Thread */
- mHandler = new Handler(mTestHandlerThread.getLooper()) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case EVENT_NETWORK_SCAN_START:
- Log.d(TAG, "request network scan");
- boolean useShellIdentity = (Boolean) msg.obj;
- if (useShellIdentity) {
- InstrumentationRegistry.getInstrumentation().getUiAutomation()
- .adoptShellPermissionIdentity();
+ mHandler =
+ new Handler(mTestHandlerThread.getLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_NETWORK_SCAN_START:
+ Log.d(TAG, "request network scan");
+ boolean useShellIdentity = (Boolean) msg.obj;
+ if (useShellIdentity) {
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .adoptShellPermissionIdentity();
+ }
+ try {
+ mNetworkScan =
+ mTelephonyManager.requestNetworkScan(
+ mNetworkScanRequest,
+ AsyncTask.SERIAL_EXECUTOR,
+ mNetworkScanCallback);
+ if (mNetworkScan == null) {
+ mNetworkScanStatus = EVENT_SCAN_DENIED;
+ setReady(true);
+ }
+ } catch (SecurityException e) {
+ mNetworkScanStatus = EVENT_SCAN_DENIED;
+ setReady(true);
+ } finally {
+ if (useShellIdentity) {
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+ }
+ break;
+ default:
+ Log.d(TAG, "Unknown Event " + msg.what);
}
- try {
- mNetworkScan = mTelephonyManager.requestNetworkScan(
- mNetworkScanRequest,
- AsyncTask.SERIAL_EXECUTOR,
- mNetworkScanCallback);
- if (mNetworkScan == null) {
- mNetworkScanStatus = EVENT_SCAN_DENIED;
- setReady(true);
- }
- } catch (SecurityException e) {
- mNetworkScanStatus = EVENT_SCAN_DENIED;
- setReady(true);
- } finally {
- if (useShellIdentity) {
- InstrumentationRegistry.getInstrumentation().getUiAutomation()
- .dropShellPermissionIdentity();
- }
- }
- break;
- default:
- Log.d(TAG, "Unknown Event " + msg.what);
- }
- }
- };
+ }
+ };
}
}
@@ -265,39 +272,35 @@
Log.d(TAG, "lte channels" + lteChannels.toString());
int ranLte = AccessNetworkConstants.AccessNetworkType.EUTRAN;
radioAccessSpecifier.add(
- new RadioAccessSpecifier(ranLte, null /* bands */,
- lteChannels.stream().mapToInt(i->i).toArray()));
+ new RadioAccessSpecifier(
+ ranLte,
+ null /* bands */,
+ lteChannels.stream().mapToInt(i -> i).toArray()));
}
if (!wcdmaChannels.isEmpty()) {
Log.d(TAG, "wcdma channels" + wcdmaChannels.toString());
int ranWcdma = AccessNetworkConstants.AccessNetworkType.UTRAN;
radioAccessSpecifier.add(
- new RadioAccessSpecifier(ranWcdma, null /* bands */,
- wcdmaChannels.stream().mapToInt(i->i).toArray()));
+ new RadioAccessSpecifier(
+ ranWcdma,
+ null /* bands */,
+ wcdmaChannels.stream().mapToInt(i -> i).toArray()));
}
if (!gsmChannels.isEmpty()) {
Log.d(TAG, "gsm channels" + gsmChannels.toString());
int ranGsm = AccessNetworkConstants.AccessNetworkType.GERAN;
radioAccessSpecifier.add(
- new RadioAccessSpecifier(ranGsm, null /* bands */,
- gsmChannels.stream().mapToInt(i->i).toArray()));
+ new RadioAccessSpecifier(
+ ranGsm,
+ null /* bands */,
+ gsmChannels.stream().mapToInt(i -> i).toArray()));
}
return radioAccessSpecifier;
}
- /**
- * Tests that the device properly requests a network scan.
- */
+ /** Tests that the device properly requests a network scan. */
@Test
public void testRequestNetworkScan() {
- if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
- // Checks whether the cellular stack should be running on this device.
- Log.e(TAG, "No cellular support, the test will be skipped.");
- return;
- }
- if (!mTelephonyManager.hasCarrierPrivileges()) {
- fail("This test requires a SIM card with carrier privilege rule on it.");
- }
boolean isLocationSwitchOn = getAndSetLocationSwitch(true);
try {
mNetworkScanRequest = buildNetworkScanRequest(true);
@@ -308,11 +311,16 @@
waitUntilReady();
Log.d(TAG, "mNetworkScanStatus: " + mNetworkScanStatus);
- assertTrue("The final scan status is " + mNetworkScanStatus + " with error code "
- + mErrorCode + ", not ScanCompleted"
- + " or ScanError with an error code ERROR_MODEM_UNAVAILABLE or"
- + " ERROR_UNSUPPORTED",
- isScanStatusValid());
+ assertWithMessage(
+ "The final scan status is "
+ + mNetworkScanStatus
+ + " with error code "
+ + mErrorCode
+ + ", not ScanCompleted"
+ + " or ScanError with an error code ERROR_MODEM_UNAVAILABLE or"
+ + " ERROR_UNSUPPORTED")
+ .that(isScanStatusValid())
+ .isTrue();
} finally {
getAndSetLocationSwitch(isLocationSwitchOn);
}
@@ -328,40 +336,36 @@
requestNetworkScanLocationOffHelper(true, true);
}
- public void requestNetworkScanLocationOffHelper(boolean includeBandsAndChannels,
- boolean useSpecialScanPermission) {
- if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
- // Checks whether the cellular stack should be running on this device.
- Log.e(TAG, "No cellular support, the test will be skipped.");
- return;
- }
- if (!mTelephonyManager.hasCarrierPrivileges()) {
- fail("This test requires a SIM card with carrier privilege rule on it.");
- }
-
+ public void requestNetworkScanLocationOffHelper(
+ boolean includeBandsAndChannels, boolean useSpecialScanPermission) {
mNetworkScanRequest = buildNetworkScanRequest(includeBandsAndChannels);
boolean isLocationSwitchOn = getAndSetLocationSwitch(false);
try {
mNetworkScanCallback = new NetworkScanCallbackImpl();
- Message startNetworkScan = mHandler.obtainMessage(EVENT_NETWORK_SCAN_START,
- useSpecialScanPermission);
+ Message startNetworkScan =
+ mHandler.obtainMessage(EVENT_NETWORK_SCAN_START, useSpecialScanPermission);
setReady(false);
startNetworkScan.sendToTarget();
waitUntilReady();
if (includeBandsAndChannels) {
// If we included the bands when location is off, expect a security error and
// nothing else.
- assertEquals(EVENT_SCAN_DENIED, mNetworkScanStatus);
+ assertThat(mNetworkScanStatus).isEqualTo(EVENT_SCAN_DENIED);
return;
}
Log.d(TAG, "mNetworkScanStatus: " + mNetworkScanStatus);
- assertTrue("The final scan status is " + mNetworkScanStatus + " with error code "
- + mErrorCode + ", not ScanCompleted"
- + " or ScanError with an error code ERROR_MODEM_UNAVAILABLE or"
- + " ERROR_UNSUPPORTED",
- isScanStatusValid());
+ assertWithMessage(
+ "The final scan status is "
+ + mNetworkScanStatus
+ + " with error code "
+ + mErrorCode
+ + ", not ScanCompleted"
+ + " or ScanError with an error code ERROR_MODEM_UNAVAILABLE or"
+ + " ERROR_UNSUPPORTED")
+ .that(isScanStatusValid())
+ .isTrue();
} finally {
getAndSetLocationSwitch(isLocationSwitchOn);
}
@@ -376,32 +380,40 @@
// Construct a NetworkScanRequest
radioAccessSpecifier = getRadioAccessSpecifier(allCellInfo);
if (!includeBandsAndChannels) {
- radioAccessSpecifier = radioAccessSpecifier.stream().map(spec ->
- new RadioAccessSpecifier(spec.getRadioAccessNetwork(), null, null))
- .collect(Collectors.toList());
+ radioAccessSpecifier =
+ radioAccessSpecifier.stream()
+ .map(
+ spec ->
+ new RadioAccessSpecifier(
+ spec.getRadioAccessNetwork(), null, null))
+ .collect(Collectors.toList());
}
}
Log.d(TAG, "number of radioAccessSpecifier: " + radioAccessSpecifier.size());
if (radioAccessSpecifier.isEmpty()) {
// Put in some arbitrary bands and channels so that we trip the location check if needed
- int[] fakeBands = includeBandsAndChannels
- ? new int[] { AccessNetworkConstants.EutranBand.BAND_5 }
- : null;
- int[] fakeChannels = includeBandsAndChannels ? new int[] { 2400 } : null;
+ int[] fakeBands =
+ includeBandsAndChannels
+ ? new int[] {AccessNetworkConstants.EutranBand.BAND_5}
+ : null;
+ int[] fakeChannels = includeBandsAndChannels ? new int[] {2400} : null;
- RadioAccessSpecifier gsm = new RadioAccessSpecifier(
- AccessNetworkConstants.AccessNetworkType.GERAN,
- null /* bands */,
- null /* channels */);
- RadioAccessSpecifier lte = new RadioAccessSpecifier(
- AccessNetworkConstants.AccessNetworkType.EUTRAN,
- fakeBands /* bands */,
- fakeChannels /* channels */);
- RadioAccessSpecifier wcdma = new RadioAccessSpecifier(
- AccessNetworkConstants.AccessNetworkType.UTRAN,
- null /* bands */,
- null /* channels */);
+ RadioAccessSpecifier gsm =
+ new RadioAccessSpecifier(
+ AccessNetworkConstants.AccessNetworkType.GERAN,
+ null /* bands */,
+ null /* channels */);
+ RadioAccessSpecifier lte =
+ new RadioAccessSpecifier(
+ AccessNetworkConstants.AccessNetworkType.EUTRAN,
+ fakeBands /* bands */,
+ fakeChannels /* channels */);
+ RadioAccessSpecifier wcdma =
+ new RadioAccessSpecifier(
+ AccessNetworkConstants.AccessNetworkType.UTRAN,
+ null /* bands */,
+ null /* channels */);
radioAccessSpecifier.add(gsm);
radioAccessSpecifier.add(lte);
radioAccessSpecifier.add(wcdma);
@@ -416,7 +428,6 @@
true /*enable incremental results*/,
5 /* incremental results periodicity */,
null /* List of PLMN ids (MCC-MNC) */);
-
}
private List<CellInfo> getCellInfo() {
@@ -432,71 +443,87 @@
@Test
public void testNetworkScanPermission() {
- PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
+ PackageManager pm = getContext().getPackageManager();
- List<Integer> specialUids = Arrays.asList(Process.SYSTEM_UID,
- Process.PHONE_UID, Process.SHELL_UID);
+ List<Integer> specialUids =
+ Arrays.asList(Process.SYSTEM_UID, Process.PHONE_UID, Process.SHELL_UID);
- List<PackageInfo> holding = pm.getPackagesHoldingPermissions(
- new String[] { NETWORK_SCAN_PERMISSION },
- PackageManager.MATCH_DISABLED_COMPONENTS);
+ List<PackageInfo> holding =
+ pm.getPackagesHoldingPermissions(
+ new String[] {NETWORK_SCAN_PERMISSION},
+ PackageManager.MATCH_DISABLED_COMPONENTS);
- List<Integer> nonSpecialPackages = holding.stream()
- .map(pi -> {
- try {
- return pm.getPackageUid(pi.packageName, 0);
- } catch (PackageManager.NameNotFoundException e) {
- return Process.INVALID_UID;
- }
- })
- .filter(uid -> !specialUids.contains(UserHandle.getAppId(uid)))
- .collect(Collectors.toList());
+ List<Integer> nonSpecialPackages =
+ holding.stream()
+ .map(
+ pi -> {
+ try {
+ return pm.getPackageUid(pi.packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ return Process.INVALID_UID;
+ }
+ })
+ .filter(uid -> !specialUids.contains(UserHandle.getAppId(uid)))
+ .collect(Collectors.toList());
- if (nonSpecialPackages.size() > 1) {
- fail("Only one app on the device is allowed to hold the NETWORK_SCAN permission.");
- }
+ assertWithMessage(
+ "Only one app on the device is allowed to hold the NETWORK_SCAN"
+ + " permission.")
+ .that(nonSpecialPackages.size())
+ .isAtMost(1);
}
private boolean getAndSetLocationSwitch(boolean enabled) {
CountDownLatch locationChangeLatch = new CountDownLatch(1);
- ContentObserver settingsObserver = new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange) {
- locationChangeLatch.countDown();
- super.onChange(selfChange);
- }
- };
+ ContentObserver settingsObserver =
+ new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ locationChangeLatch.countDown();
+ super.onChange(selfChange);
+ }
+ };
- InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
.adoptShellPermissionIdentity();
+ ContentResolver contentResolver = getContext().getContentResolver();
try {
- int oldLocationMode = Settings.Secure.getInt(
- InstrumentationRegistry.getContext().getContentResolver(),
- Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
+ int oldLocationMode =
+ Settings.Secure.getInt(
+ contentResolver,
+ Settings.Secure.LOCATION_MODE,
+ Settings.Secure.LOCATION_MODE_OFF);
- int locationMode = enabled ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
- : Settings.Secure.LOCATION_MODE_OFF;
+ int locationMode =
+ enabled
+ ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
+ : Settings.Secure.LOCATION_MODE_OFF;
if (locationMode != oldLocationMode) {
- InstrumentationRegistry.getContext().getContentResolver().registerContentObserver(
+ contentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE),
- false, settingsObserver);
- Settings.Secure.putInt(InstrumentationRegistry.getContext().getContentResolver(),
- Settings.Secure.LOCATION_MODE, locationMode);
+ false,
+ settingsObserver);
+ Settings.Secure.putInt(
+ contentResolver, Settings.Secure.LOCATION_MODE, locationMode);
try {
- assertTrue(locationChangeLatch.await(LOCATION_SETTING_CHANGE_WAIT_MS,
- TimeUnit.MILLISECONDS));
+ assertThat(
+ locationChangeLatch.await(
+ LOCATION_SETTING_CHANGE_WAIT_MS, TimeUnit.MILLISECONDS))
+ .isTrue();
} catch (InterruptedException e) {
- Log.w(NetworkScanApiTest.class.getSimpleName(),
+ Log.w(
+ NetworkScanApiTest.class.getSimpleName(),
"Interrupted while waiting for location settings change. Test results"
- + " may not be accurate.");
+ + " may not be accurate.");
} finally {
- InstrumentationRegistry.getContext().getContentResolver()
- .unregisterContentObserver(settingsObserver);
+ contentResolver.unregisterContentObserver(settingsObserver);
}
}
return oldLocationMode == Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
} finally {
- InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
.dropShellPermissionIdentity();
}
}
@@ -509,7 +536,7 @@
}
if ((mNetworkScanStatus == EVENT_NETWORK_SCAN_ERROR)
&& ((mErrorCode == NetworkScan.ERROR_MODEM_UNAVAILABLE)
- || (mErrorCode == NetworkScan.ERROR_UNSUPPORTED))) {
+ || (mErrorCode == NetworkScan.ERROR_UNSUPPORTED))) {
// Scan error but the error type is allowed.
return true;
}
@@ -523,130 +550,140 @@
return mccMncs;
}
- /**
- * To test its constructor and getters.
- */
+ /** To test its constructor and getters. */
@Test
- public void testNetworkScanRequest_ConstructorAndGetters() {
- NetworkScanRequest networkScanRequest = new NetworkScanRequest(
- SCAN_TYPE,
- RADIO_ACCESS_SPECIFIERS,
- SEARCH_PERIODICITY_SEC,
- MAX_SEARCH_TIME_SEC,
- INCREMENTAL_RESULTS,
- INCREMENTAL_RESULTS_PERIODICITY_SEC,
- getPlmns());
+ public void testNetworkScanRequest_constructorAndGetters() {
+ NetworkScanRequest networkScanRequest =
+ new NetworkScanRequest(
+ SCAN_TYPE,
+ RADIO_ACCESS_SPECIFIERS,
+ SEARCH_PERIODICITY_SEC,
+ MAX_SEARCH_TIME_SEC,
+ INCREMENTAL_RESULTS,
+ INCREMENTAL_RESULTS_PERIODICITY_SEC,
+ getPlmns());
- assertEquals("getScanType() returns wrong value",
- SCAN_TYPE, networkScanRequest.getScanType());
- assertEquals("getSpecifiers() returns wrong value",
- RADIO_ACCESS_SPECIFIERS, networkScanRequest.getSpecifiers());
- assertEquals("getSearchPeriodicity() returns wrong value",
- SEARCH_PERIODICITY_SEC, networkScanRequest.getSearchPeriodicity());
- assertEquals("getMaxSearchTime() returns wrong value",
- MAX_SEARCH_TIME_SEC, networkScanRequest.getMaxSearchTime());
- assertEquals("getIncrementalResults() returns wrong value",
- INCREMENTAL_RESULTS, networkScanRequest.getIncrementalResults());
- assertEquals("getIncrementalResultsPeriodicity() returns wrong value",
- INCREMENTAL_RESULTS_PERIODICITY_SEC,
- networkScanRequest.getIncrementalResultsPeriodicity());
- assertEquals("getPlmns() returns wrong value", getPlmns(), networkScanRequest.getPlmns());
- assertEquals("describeContents() returns wrong value",
- 0, networkScanRequest.describeContents());
+ assertWithMessage("getScanType() returns wrong value")
+ .that(networkScanRequest.getScanType())
+ .isEqualTo(SCAN_TYPE);
+ assertWithMessage("getSpecifiers() returns wrong value")
+ .that(networkScanRequest.getSpecifiers())
+ .isEqualTo(RADIO_ACCESS_SPECIFIERS);
+ assertWithMessage("getSearchPeriodicity() returns wrong value")
+ .that(networkScanRequest.getSearchPeriodicity())
+ .isEqualTo(SEARCH_PERIODICITY_SEC);
+ assertWithMessage("getMaxSearchTime() returns wrong value")
+ .that(networkScanRequest.getMaxSearchTime())
+ .isEqualTo(MAX_SEARCH_TIME_SEC);
+ assertWithMessage("getIncrementalResults() returns wrong value")
+ .that(networkScanRequest.getIncrementalResults())
+ .isEqualTo(INCREMENTAL_RESULTS);
+ assertWithMessage("getIncrementalResultsPeriodicity() returns wrong value")
+ .that(networkScanRequest.getIncrementalResultsPeriodicity())
+ .isEqualTo(INCREMENTAL_RESULTS_PERIODICITY_SEC);
+ assertWithMessage("getPlmns() returns wrong value")
+ .that(networkScanRequest.getPlmns())
+ .isEqualTo(getPlmns());
+ assertWithMessage("describeContents() returns wrong value")
+ .that(networkScanRequest.describeContents())
+ .isEqualTo(0);
}
- /**
- * To test its hashCode method.
- */
+ /** To test its hashCode method. */
@Test
- public void testNetworkScanRequestParcel_Hashcode() {
- NetworkScanRequest networkScanRequest1 = new NetworkScanRequest(
- SCAN_TYPE,
- RADIO_ACCESS_SPECIFIERS,
- SEARCH_PERIODICITY_SEC,
- MAX_SEARCH_TIME_SEC,
- INCREMENTAL_RESULTS,
- INCREMENTAL_RESULTS_PERIODICITY_SEC,
- getPlmns());
+ public void testNetworkScanRequestParcel_hashCode() {
+ NetworkScanRequest networkScanRequest1 =
+ new NetworkScanRequest(
+ SCAN_TYPE,
+ RADIO_ACCESS_SPECIFIERS,
+ SEARCH_PERIODICITY_SEC,
+ MAX_SEARCH_TIME_SEC,
+ INCREMENTAL_RESULTS,
+ INCREMENTAL_RESULTS_PERIODICITY_SEC,
+ getPlmns());
- NetworkScanRequest networkScanRequest2 = new NetworkScanRequest(
- SCAN_TYPE,
- RADIO_ACCESS_SPECIFIERS,
- SEARCH_PERIODICITY_SEC,
- MAX_SEARCH_TIME_SEC,
- INCREMENTAL_RESULTS,
- INCREMENTAL_RESULTS_PERIODICITY_SEC,
- getPlmns());
+ NetworkScanRequest networkScanRequest2 =
+ new NetworkScanRequest(
+ SCAN_TYPE,
+ RADIO_ACCESS_SPECIFIERS,
+ SEARCH_PERIODICITY_SEC,
+ MAX_SEARCH_TIME_SEC,
+ INCREMENTAL_RESULTS,
+ INCREMENTAL_RESULTS_PERIODICITY_SEC,
+ getPlmns());
- NetworkScanRequest networkScanRequest3 = new NetworkScanRequest(
- SCAN_TYPE,
- null,
- SEARCH_PERIODICITY_SEC,
- MAX_SEARCH_TIME_SEC,
- false,
- 0,
- getPlmns());
+ NetworkScanRequest networkScanRequest3 =
+ new NetworkScanRequest(
+ SCAN_TYPE,
+ null,
+ SEARCH_PERIODICITY_SEC,
+ MAX_SEARCH_TIME_SEC,
+ false,
+ 0,
+ getPlmns());
- assertEquals("hashCode() returns different hash code for same objects",
- networkScanRequest1.hashCode(), networkScanRequest2.hashCode());
- assertNotSame("hashCode() returns same hash code for different objects",
- networkScanRequest1.hashCode(), networkScanRequest3.hashCode());
+ assertWithMessage("hashCode() returns different hash code for same objects")
+ .that(networkScanRequest1.hashCode())
+ .isEqualTo(networkScanRequest2.hashCode());
+ assertWithMessage("hashCode() returns same hash code for different objects")
+ .that(networkScanRequest1.hashCode())
+ .isNotEqualTo(networkScanRequest3.hashCode());
}
- /**
- * To test its comparision method.
- */
+ /** To test its comparison method. */
@Test
- public void testNetworkScanRequestParcel_Equals() {
- NetworkScanRequest networkScanRequest1 = new NetworkScanRequest(
- SCAN_TYPE,
- RADIO_ACCESS_SPECIFIERS,
- SEARCH_PERIODICITY_SEC,
- MAX_SEARCH_TIME_SEC,
- INCREMENTAL_RESULTS,
- INCREMENTAL_RESULTS_PERIODICITY_SEC,
- getPlmns());
+ public void testNetworkScanRequestParcel_equals() {
+ NetworkScanRequest networkScanRequest1 =
+ new NetworkScanRequest(
+ SCAN_TYPE,
+ RADIO_ACCESS_SPECIFIERS,
+ SEARCH_PERIODICITY_SEC,
+ MAX_SEARCH_TIME_SEC,
+ INCREMENTAL_RESULTS,
+ INCREMENTAL_RESULTS_PERIODICITY_SEC,
+ getPlmns());
- NetworkScanRequest networkScanRequest2 = new NetworkScanRequest(
- SCAN_TYPE,
- RADIO_ACCESS_SPECIFIERS,
- SEARCH_PERIODICITY_SEC,
- MAX_SEARCH_TIME_SEC,
- INCREMENTAL_RESULTS,
- INCREMENTAL_RESULTS_PERIODICITY_SEC,
- getPlmns());
+ NetworkScanRequest networkScanRequest2 =
+ new NetworkScanRequest(
+ SCAN_TYPE,
+ RADIO_ACCESS_SPECIFIERS,
+ SEARCH_PERIODICITY_SEC,
+ MAX_SEARCH_TIME_SEC,
+ INCREMENTAL_RESULTS,
+ INCREMENTAL_RESULTS_PERIODICITY_SEC,
+ getPlmns());
- assertTrue(networkScanRequest1.equals(networkScanRequest2));
+ assertThat(networkScanRequest1).isEqualTo(networkScanRequest2);
- networkScanRequest2 = new NetworkScanRequest(
- SCAN_TYPE,
- RADIO_ACCESS_SPECIFIERS,
- SEARCH_PERIODICITY_SEC,
- MAX_SEARCH_TIME_SEC,
- INCREMENTAL_RESULTS,
- INCREMENTAL_RESULTS_PERIODICITY_SEC,
- null /* List of PLMN ids (MCC-MNC) */);
- assertFalse(networkScanRequest1.equals(networkScanRequest2));
+ networkScanRequest2 =
+ new NetworkScanRequest(
+ SCAN_TYPE,
+ RADIO_ACCESS_SPECIFIERS,
+ SEARCH_PERIODICITY_SEC,
+ MAX_SEARCH_TIME_SEC,
+ INCREMENTAL_RESULTS,
+ INCREMENTAL_RESULTS_PERIODICITY_SEC,
+ null /* List of PLMN ids (MCC-MNC) */);
+ assertThat(networkScanRequest1).isNotEqualTo(networkScanRequest2);
}
- /**
- * To test its writeToParcel and createFromParcel methods.
- */
+ /** To test its writeToParcel and createFromParcel methods. */
@Test
- public void testNetworkScanRequestParcel_Parcel() {
- NetworkScanRequest networkScanRequest = new NetworkScanRequest(
- SCAN_TYPE,
- null /* Radio Access Specifier */,
- SEARCH_PERIODICITY_SEC,
- MAX_SEARCH_TIME_SEC,
- INCREMENTAL_RESULTS,
- INCREMENTAL_RESULTS_PERIODICITY_SEC,
- getPlmns());
+ public void testNetworkScanRequestParcel_parcel() {
+ NetworkScanRequest networkScanRequest =
+ new NetworkScanRequest(
+ SCAN_TYPE,
+ null /* Radio Access Specifier */,
+ SEARCH_PERIODICITY_SEC,
+ MAX_SEARCH_TIME_SEC,
+ INCREMENTAL_RESULTS,
+ INCREMENTAL_RESULTS_PERIODICITY_SEC,
+ getPlmns());
Parcel p = Parcel.obtain();
networkScanRequest.writeToParcel(p, 0);
p.setDataPosition(0);
NetworkScanRequest newnsr = NetworkScanRequest.CREATOR.createFromParcel(p);
- assertTrue(networkScanRequest.equals(newnsr));
+ assertThat(networkScanRequest).isEqualTo(newnsr);
}
}
diff --git a/tests/tests/content/OWNERS b/tests/tests/content/OWNERS
index 12c955a..737382c 100644
--- a/tests/tests/content/OWNERS
+++ b/tests/tests/content/OWNERS
@@ -3,3 +3,4 @@
patb@google.com
schfan@google.com
alexbuy@google.com
+rtmitchell@google.com
diff --git a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
index 8ae80df..03a638c 100644
--- a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
+++ b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
@@ -494,6 +494,9 @@
}
public void testPowerUsageSummarySettings() {
+ if(FeatureUtil.isWatch()){
+ return;
+ }
if (isBatteryPresent()) {
assertCanBeHandled(new Intent(Intent.ACTION_POWER_USAGE_SUMMARY));
}
@@ -517,6 +520,9 @@
}
public void testRequestSetAutofillServiceIntent() {
+ if (FeatureUtil.isWatch()) {
+ return;
+ }
Intent intent = new Intent(Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE)
.setData(Uri.parse("package:android.content.cts"));
assertCanBeHandled(intent);
diff --git a/tests/tests/content/src/android/content/cts/ClipboardManagerTest.java b/tests/tests/content/src/android/content/cts/ClipboardManagerTest.java
index 4d4c079..121999e 100644
--- a/tests/tests/content/src/android/content/cts/ClipboardManagerTest.java
+++ b/tests/tests/content/src/android/content/cts/ClipboardManagerTest.java
@@ -21,6 +21,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.Activity;
import android.content.ClipData;
@@ -31,6 +32,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.net.Uri;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
@@ -49,13 +51,13 @@
@RunWith(AndroidJUnit4.class)
//@AppModeFull // TODO(Instant) Should clip board data be visible?
public class ClipboardManagerTest {
- private Context mContext;
+ private final Context mContext = InstrumentationRegistry.getTargetContext();
private ClipboardManager mClipboardManager;
private UiDevice mUiDevice;
@Before
public void setUp() throws Exception {
- mContext = InstrumentationRegistry.getTargetContext();
+ assumeTrue("Skipping Test: Wear-Os does not support ClipboardService", hasAutoFillFeature());
mClipboardManager = mContext.getSystemService(ClipboardManager.class);
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
mUiDevice.wakeUp();
@@ -365,4 +367,9 @@
assertNull(item.getUri());
}
}
+
+ private boolean hasAutoFillFeature() {
+ return mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUTOFILL);
+ }
}
diff --git a/tests/tests/content/src/android/content/cts/wm/OWNERS b/tests/tests/content/src/android/content/cts/wm/OWNERS
deleted file mode 100644
index 940ab87..0000000
--- a/tests/tests/content/src/android/content/cts/wm/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-include /tests/framework/base/windowmanager/OWNERS
-charlesccchen@google.com
diff --git a/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java b/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
index 358a894..20752f1 100644
--- a/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ApplicationInfoTest.java
@@ -30,11 +30,14 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNotNull;
import android.content.Context;
import android.content.cts.R;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Environment;
import android.os.Parcel;
import android.os.Process;
import android.os.UserHandle;
@@ -44,6 +47,8 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.SystemUtil;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -275,4 +280,55 @@
p.restoreAllowSquashing(prevSquashing);
}
+
+ @Test
+ public void testIsProduct() throws Exception {
+ final String packageName = getPartitionFirstPackageName(
+ Environment.getProductDirectory().getAbsolutePath());
+ assertNotNull(packageName);
+
+ final PackageInfo info = getContext().getPackageManager().getPackageInfo(
+ packageName.trim(), 0 /* flags */);
+ assertTrue(info.applicationInfo.isProduct());
+ }
+
+ @Test
+ public void testIsVendor() throws Exception {
+ final String packageName = getPartitionFirstPackageName(
+ Environment.getVendorDirectory().getAbsolutePath());
+ assertNotNull(packageName);
+
+ final PackageInfo info = getContext().getPackageManager().getPackageInfo(
+ packageName.trim(), 0 /* flags */);
+ assertTrue(info.applicationInfo.isVendor());
+ }
+
+ @Test
+ public void testIsOem() throws Exception {
+ final String packageName = getPartitionFirstPackageName(
+ Environment.getOemDirectory().getAbsolutePath());
+ // Oem package may not exist in every builds like aosp.
+ assumeNotNull(packageName);
+
+ final PackageInfo info = getContext().getPackageManager().getPackageInfo(
+ packageName.trim(), 0 /* flags */);
+ assertTrue(info.applicationInfo.isOem());
+ }
+
+ private String getPartitionFirstPackageName(final String partition) throws Exception {
+ // List package with "-f" option which contains package direction, use that to distinguish
+ // package partition and find out target package.
+ final String output = SystemUtil.runShellCommand(
+ InstrumentationRegistry.getInstrumentation(), "pm list package -f -s");
+ final String[] packages = output.split("package:");
+ for (int i = 0; i < packages.length; i++) {
+ // Split package info to direction and name.
+ String[] info = packages[i].split("\\.apk=");
+ if (info.length != 2) continue; // Package info need include direction and name.
+ if (info[0] != null && info[0].startsWith(partition)) {
+ return info[1]; // Package name.
+ }
+ }
+ return null;
+ }
}
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java
index 75f7cc4..3db58e2 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java
@@ -29,7 +29,6 @@
import android.os.ParcelFileDescriptor;
import android.platform.test.annotations.AppModeFull;
import android.service.dataloader.DataLoaderService;
-import android.text.TextUtils;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
@@ -53,6 +52,9 @@
import java.io.Reader;
import java.util.Arrays;
import java.util.Optional;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -233,28 +235,38 @@
@LargeTest
@Test
- public void testInstallSysTrace() throws Exception {
- // Async atrace dump uses less resources but requires periodic pulls.
- // Overall timeout of 30secs in 100ms intervals should be enough.
- final int atraceDumpIterations = 300;
- final int atraceDumpDelayMs = 100;
+ public void testInstallSysTraceDebuggable() throws Exception {
+ doTestInstallSysTrace(TEST_APK);
+ }
- final String expected = "|page_read:";
- final ByteArrayOutputStream result = new ByteArrayOutputStream();
+ private boolean checkSysTraceForSubstring(String testApk, final String expected,
+ int atraceDumpIterations, int atraceDumpDelayMs) throws Exception {
+ return checkSysTrace(
+ atraceDumpIterations,
+ atraceDumpDelayMs,
+ () -> installPackage(testApk),
+ (stdout) -> stdout.contains(expected));
+ }
+
+ private boolean checkSysTrace(
+ int atraceDumpIterations,
+ int atraceDumpDelayMs,
+ final Callable<Void> installer,
+ final Function<String, Boolean> checker)
+ throws Exception {
+ final int beforeReadDelayMs = 1000;
+
+ final CompletableFuture<Boolean> result = new CompletableFuture<>();
final Thread readFromProcess = new Thread(() -> {
try {
executeShellCommand("atrace --async_start -b 1024 -c adb");
try {
for (int i = 0; i < atraceDumpIterations; ++i) {
- final ParcelFileDescriptor stdout = getUiAutomation().executeShellCommand(
- "atrace --async_dump");
- try (InputStream inputStream =
- new ParcelFileDescriptor.AutoCloseInputStream(
- stdout)) {
- final String found = waitForSubstring(inputStream, expected);
- if (!TextUtils.isEmpty(found)) {
- result.write(found.getBytes());
- return;
+ final String stdout = executeShellCommand("atrace --async_dump");
+ try {
+ if (checker.apply(stdout)) {
+ result.complete(true);
+ break;
}
Thread.currentThread().sleep(atraceDumpDelayMs);
} catch (InterruptedException ignored) {
@@ -269,13 +281,27 @@
readFromProcess.start();
for (int i = 0; i < 3; ++i) {
- installPackage(TEST_APK);
+ installer.call();
assertTrue(isAppInstalled(TEST_APP_PACKAGE));
+ Thread.currentThread().sleep(beforeReadDelayMs);
uninstallPackageSilently(TEST_APP_PACKAGE);
}
readFromProcess.join();
- assertNotEquals(0, result.size());
+ return result.getNow(false);
+ }
+
+ private void doTestInstallSysTrace(String testApk) throws Exception {
+ // Async atrace dump uses less resources but requires periodic pulls.
+ // Overall timeout of 10secs in 100ms intervals should be enough.
+ final int atraceDumpIterations = 100;
+ final int atraceDumpDelayMs = 100;
+ final String expected = "|page_read:";
+
+ assertTrue(
+ "No page reads (" + expected + ") found in atrace dump",
+ checkSysTraceForSubstring(testApk, expected, atraceDumpIterations,
+ atraceDumpDelayMs));
}
private boolean isAppInstalled(String packageName) throws IOException {
@@ -302,10 +328,11 @@
return TEST_APK_PATH + baseName;
}
- private void installPackage(String baseName) throws IOException {
+ private Void installPackage(String baseName) throws IOException {
File file = new File(createApkPath(baseName));
assertEquals("Success\n",
executeShellCommand("pm install-incremental -t -g " + file.getPath()));
+ return null;
}
private String uninstallPackageSilently(String packageName) throws IOException {
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 726e5de..5719872 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
@@ -16,6 +16,7 @@
package android.content.pm.cts;
+import static android.Manifest.permission.INSTALL_TEST_ONLY_PACKAGE;
import static android.content.pm.ApplicationInfo.FLAG_HAS_CODE;
import static android.content.pm.ApplicationInfo.FLAG_INSTALLED;
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
@@ -108,6 +109,7 @@
private static final int NUM_OF_ACTIVITIES_IN_MANIFEST = 12;
private static final String SHIM_APEX_PACKAGE_NAME = "com.android.apex.cts.shim";
+ private static final String SHELL_PACKAGE_NAME = "com.android.shell";
@Before
public void setup() throws Exception {
@@ -990,4 +992,13 @@
assertThat(packageInfo.signatures)
.asList().containsExactly((Object[]) pastSigningCertificates);
}
+
+ @Test
+ public void testInstallTestOnlyPackagePermission_onlyGrantedToShell() {
+ List<PackageInfo> packages = mPackageManager.getPackagesHoldingPermissions(
+ new String[]{INSTALL_TEST_ONLY_PACKAGE}, /* flags= */ 0);
+
+ assertThat(packages).hasSize(1);
+ assertThat(packages.get(0).packageName).isEqualTo(SHELL_PACKAGE_NAME);
+ }
}
diff --git a/tests/tests/content/src/android/content/wm/cts/OWNERS b/tests/tests/content/src/android/content/wm/cts/OWNERS
new file mode 100644
index 0000000..5ed5c56
--- /dev/null
+++ b/tests/tests/content/src/android/content/wm/cts/OWNERS
@@ -0,0 +1,2 @@
+include platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS
+charlesccchen@google.com
diff --git a/tests/tests/graphics/jni/android_graphics_cts_VulkanPreTransformCtsActivity.cpp b/tests/tests/graphics/jni/android_graphics_cts_VulkanPreTransformCtsActivity.cpp
index c9f557f53..8d50dfd 100644
--- a/tests/tests/graphics/jni/android_graphics_cts_VulkanPreTransformCtsActivity.cpp
+++ b/tests/tests/graphics/jni/android_graphics_cts_VulkanPreTransformCtsActivity.cpp
@@ -65,9 +65,10 @@
for (uint32_t i = 0; i < 120; ++i) {
ret = renderer.drawFrame();
if (setPreTransform || preTransformHint == 0x1 /*VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR*/) {
- ASSERT(ret == VK_TEST_SUCCESS, "Failed to draw frame");
+ ASSERT(ret == VK_TEST_SUCCESS, "Failed to draw frame(%u) ret(%d)", i, (int)ret);
} else {
- ASSERT(ret == VK_TEST_SUCCESS_SUBOPTIMAL, "Failed to draw suboptimal frame");
+ ASSERT(ret == VK_TEST_SUCCESS_SUBOPTIMAL, "Failed to draw suboptimal frame(%u) ret(%d)",
+ i, (int)ret);
}
}
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
index 0433205..ac3e111 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
@@ -2144,15 +2144,15 @@
Debug.getMemoryInfo(end);
assertNotEquals(0, start.getTotalPss());
assertNotEquals(0, end.getTotalPss());
- if (end.getTotalPss() - start.getTotalPss() > 2000 /* kB */) {
+ if (end.getTotalPss() - start.getTotalPss() > 5000 /* kB */) {
runGcAndFinalizersSync();
Debug.getMemoryInfo(end);
- if (end.getTotalPss() - start.getTotalPss() > 4000 /* kB */) {
+ if (end.getTotalPss() - start.getTotalPss() > 7000 /* kB */) {
// Guarded by if so we don't continually generate garbage for the
// assertion string.
assertEquals("Memory leaked, iteration=" + iteration,
start.getTotalPss(), end.getTotalPss(),
- 4000 /* kb */);
+ 7000 /* kb */);
}
}
}
diff --git a/tests/tests/graphics/src/android/graphics/cts/VulkanPreTransformTest.java b/tests/tests/graphics/src/android/graphics/cts/VulkanPreTransformTest.java
index 14d3000..f14e60c 100644
--- a/tests/tests/graphics/src/android/graphics/cts/VulkanPreTransformTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/VulkanPreTransformTest.java
@@ -120,6 +120,7 @@
return;
}
sActivity = mActivityRule.launchActivity(null);
+ SystemClock.sleep(5000);
sActivity.testVulkanPreTransform(true);
sActivity.finish();
sActivity = null;
@@ -134,6 +135,7 @@
return;
}
sActivity = mActivityRule.launchActivity(null);
+ SystemClock.sleep(5000);
sActivity.testVulkanPreTransform(false);
sActivity.finish();
sActivity = null;
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/InputCtsActivity.java b/tests/tests/hardware/src/android/hardware/input/cts/InputCtsActivity.java
index 028b18e..6a94327 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/InputCtsActivity.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/InputCtsActivity.java
@@ -21,10 +21,13 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
+import java.util.function.Consumer;
+
public class InputCtsActivity extends Activity {
private static final String TAG = "InputCtsActivity";
private InputCallback mInputCallback;
+ private Consumer<Boolean> mPointerCaptureCallback;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -63,7 +66,18 @@
return true;
}
+ @Override
+ public void onPointerCaptureChanged(boolean hasCapture) {
+ if (mPointerCaptureCallback != null) {
+ mPointerCaptureCallback.accept(hasCapture);
+ }
+ }
+
public void setInputCallback(InputCallback callback) {
mInputCallback = callback;
}
+
+ public void setPointerCaptureCallback(Consumer<Boolean> callback) {
+ mPointerCaptureCallback = callback;
+ }
}
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
index 6239026..2113306 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
@@ -32,6 +32,7 @@
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
+import com.android.compatibility.common.util.PollingCheck;
import com.android.cts.input.HidDevice;
import com.android.cts.input.HidJsonParser;
import com.android.cts.input.HidTestData;
@@ -43,6 +44,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -337,22 +339,50 @@
}
}
+ protected void requestFocusSync() {
+ mActivityRule.getActivity().runOnUiThread(() -> {
+ mDecorView.setFocusable(true);
+ mDecorView.setFocusableInTouchMode(true);
+ mDecorView.requestFocus();
+ });
+ PollingCheck.waitFor(mDecorView::hasFocus);
+ }
+
protected class PointerCaptureSession implements AutoCloseable {
protected PointerCaptureSession() {
- requestPointerCaptureSync();
+ requestFocusSync();
+ ensurePointerCaptureState(true);
}
@Override
public void close() {
- releasePointerCaptureSync();
+ ensurePointerCaptureState(false);
}
- private void requestPointerCaptureSync() {
- mInstrumentation.runOnMainSync(mDecorView::requestPointerCapture);
- }
-
- private void releasePointerCaptureSync() {
- mInstrumentation.runOnMainSync(mDecorView::releasePointerCapture);
+ private void ensurePointerCaptureState(boolean enable) {
+ final CountDownLatch latch = new CountDownLatch(1);
+ mActivityRule.getActivity().setPointerCaptureCallback(hasCapture -> {
+ if (enable == hasCapture) {
+ latch.countDown();
+ }
+ });
+ mActivityRule.getActivity().runOnUiThread(enable ? mDecorView::requestPointerCapture
+ : mDecorView::releasePointerCapture);
+ try {
+ if (!latch.await(60, TimeUnit.SECONDS)) {
+ throw new IllegalStateException(
+ "Did not receive callback after "
+ + (enable ? "enabling" : "disabling")
+ + " Pointer Capture.");
+ }
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(
+ "Interrupted while waiting for Pointer Capture state.");
+ } finally {
+ mActivityRule.getActivity().setPointerCaptureCallback(null);
+ }
+ assertEquals("The view's Pointer Capture state did not match.", enable,
+ mDecorView.hasPointerCapture());
}
}
}
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/NintendoSwitchProTest.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/NintendoSwitchProTest.java
index c826b59..1e3c3b0 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/NintendoSwitchProTest.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/NintendoSwitchProTest.java
@@ -16,6 +16,10 @@
package android.hardware.input.cts.tests;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assume.assumeFalse;
+
+import android.content.pm.PackageManager;
import android.hardware.cts.R;
import android.os.SystemClock;
@@ -49,11 +53,18 @@
@Test
public void testAllKeys() {
+ assumeFalse("Skipping test for wear devices", isWatch());
testInputEvents(R.raw.nintendo_switchpro_keyeventtests);
}
@Test
public void testAllMotions() {
+ assumeFalse("Skipping test for wear devices", isWatch());
testInputEvents(R.raw.nintendo_switchpro_motioneventtests);
}
+
+ static boolean isWatch() {
+ final PackageManager pm = getInstrumentation().getContext().getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
+ }
}
diff --git a/tests/tests/icu/CtsIcu4cTestCases.xml b/tests/tests/icu/CtsIcu4cTestCases.xml
index c216b3a..3ef1629 100644
--- a/tests/tests/icu/CtsIcu4cTestCases.xml
+++ b/tests/tests/icu/CtsIcu4cTestCases.xml
@@ -36,8 +36,8 @@
<option name="push" value="icu4c_test_data.zip->/data/local/tmp/icu4c_test_data.zip" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="mkdir -p /data/local/tmp/test/testdata && unzip -o -d /data/local/tmp/test/testdata /data/local/tmp/icu4c_test_data.zip" />
- <option name="teardown-command" value="rm -r /data/local/tmp/test/testdata" />
+ <option name="run-command" value="unzip -o -d /data/local/tmp/ /data/local/tmp/icu4c_test_data.zip" />
+ <option name="teardown-command" value="rm -r /data/local/tmp/test /data/local/tmp/data" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tests/tests/icu/resources/android/icu/cts/expectations/icu-known-failures.txt b/tests/tests/icu/resources/android/icu/cts/expectations/icu-known-failures.txt
index e68fcd9..1b1535a 100644
--- a/tests/tests/icu/resources/android/icu/cts/expectations/icu-known-failures.txt
+++ b/tests/tests/icu/resources/android/icu/cts/expectations/icu-known-failures.txt
@@ -2,14 +2,6 @@
* This file contains expectations for tests that are known to fail.
*/
[
-// Uncomment this to exclude all tests and then add result: "SUCCESS" to any specific tests that
-// need to be run.
-/*
-{
- description: "Exclude all tests",
- name: "android.icu.dev.test"
-},
-*/
{
description: "Serialized forms have not been converted to use repackaged classes",
name: "android.icu.dev.test.format.NumberFormatRegressionTest#TestSerialization",
@@ -19,22 +11,5 @@
description: "Checks differences in DecimalFormat classes from ICU4J and JDK but on Android java.text.DecimalFormat is implemented in terms of ICU4J",
name: "android.icu.dev.test.format.NumberFormatTest#TestDataDrivenJDK",
bug: "27711713"
-},
-{
- description: "Collation rules data has been removed from ICU4J data on Android",
- names: [
- "android.icu.dev.test.collator.CollationCreationMethodTest#TestRuleVsLocaleCreationMonkey",
- "android.icu.dev.test.collator.CollationMiscTest#TestImport",
- "android.icu.dev.test.collator.CollationMiscTest#TestImportWithType",
- "android.icu.dev.test.collator.CollationMiscTest#TestUCARules",
- "android.icu.dev.test.collator.CollationTest#TestDataDriven",
- "android.icu.dev.test.collator.G7CollationTest#TestG7Data"
- ],
- bug: "27552651"
-},
-{
- description: "Unknown Language != Unknown language",
- name: "android.icu.dev.test.TestLocaleNamePackaging#testLanguageDisplayNames",
- bug: "33447162"
}
]
diff --git a/tests/tests/identity/TEST_MAPPING b/tests/tests/identity/TEST_MAPPING
new file mode 100644
index 0000000..87707a8
--- /dev/null
+++ b/tests/tests/identity/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsIdentityTestCases"
+ }
+ ]
+}
diff --git a/tests/tests/identity/src/android/security/identity/cts/UserAuthTest.java b/tests/tests/identity/src/android/security/identity/cts/UserAuthTest.java
index cc44f36..857ced0 100644
--- a/tests/tests/identity/src/android/security/identity/cts/UserAuthTest.java
+++ b/tests/tests/identity/src/android/security/identity/cts/UserAuthTest.java
@@ -118,6 +118,13 @@
mLockCredential.gotoKeyguard();
mLockCredential.enterAndConfirmLockCredential();
launchHomeActivity();
+ Context appContext = InstrumentationRegistry.getTargetContext();
+ KeyguardManager keyguardManager = (KeyguardManager)appContext.
+ getSystemService(Context.KEYGUARD_SERVICE);
+ for (int i = 0; i < 5 && keyguardManager.isDeviceLocked(); i++) {
+ Log.w(TAG, "Wait for keyguardManager unlock device ...");
+ SystemClock.sleep(1000);
+ }
}
@Override
diff --git a/tests/tests/jni/libjnitest/Android.bp b/tests/tests/jni/libjnitest/Android.bp
index de15f35..5554d96 100644
--- a/tests/tests/jni/libjnitest/Android.bp
+++ b/tests/tests/jni/libjnitest/Android.bp
@@ -33,11 +33,11 @@
"helper.c",
"register.c",
],
+ header_libs: ["libnativehelper_header_only"],
static_libs: ["libbase_ndk"],
shared_libs: [
"libdl",
"liblog",
- "libnativehelper_compat_libc++",
],
sdk_version: "current",
stl: "c++_static",
diff --git a/tests/tests/jni/libjnitest/android_jni_cts_BasicLoaderTest.cpp b/tests/tests/jni/libjnitest/android_jni_cts_BasicLoaderTest.cpp
index 704cd4f..8fc8d4e 100644
--- a/tests/tests/jni/libjnitest/android_jni_cts_BasicLoaderTest.cpp
+++ b/tests/tests/jni/libjnitest/android_jni_cts_BasicLoaderTest.cpp
@@ -19,9 +19,11 @@
*/
#include <dlfcn.h>
+#include <errno.h>
#include <jni.h>
#include <libgen.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -29,9 +31,8 @@
#include <string>
-#include "nativehelper/JNIHelp.h"
-#include "nativehelper/ScopedLocalRef.h"
-#include "nativehelper/ScopedUtfChars.h"
+#include "nativehelper/scoped_local_ref.h"
+#include "nativehelper/scoped_utf_chars.h"
static constexpr const char* kTestLibName = "libjni_test_dlclose.so";
diff --git a/tests/tests/jni/libjnitest/android_jni_cts_InstanceNonce.c b/tests/tests/jni/libjnitest/android_jni_cts_InstanceNonce.c
index cb44b42a..597f03b 100644
--- a/tests/tests/jni/libjnitest/android_jni_cts_InstanceNonce.c
+++ b/tests/tests/jni/libjnitest/android_jni_cts_InstanceNonce.c
@@ -20,11 +20,12 @@
*/
#include <jni.h>
-#include <nativehelper/JNIHelp.h>
#include <stdbool.h>
#include <string.h>
+#include "helper.h"
+
// public native void nop();
static void InstanceNonce_nop(JNIEnv *env, jobject this) {
// This space intentionally left blank.
@@ -107,8 +108,7 @@
}
if (stringClass == NULL) {
- jniThrowException(env, "java/lang/AssertionError",
- "class String not found");
+ throwException(env, "java/lang/AssertionError", "class String not found");
return NULL;
}
@@ -236,8 +236,7 @@
length = (*env)->GetStringUTFLength(env, v6);
if (length != 3) {
- jniThrowException(env, "java/lang/AssertionError",
- "bad string length");
+ throwException(env, "java/lang/AssertionError", "bad string length");
return false;
}
@@ -252,8 +251,7 @@
length = (*env)->GetArrayLength(env, v9);
if (length != 2) {
- jniThrowException(env, "java/lang/AssertionError",
- "bad array length");
+ throwException(env, "java/lang/AssertionError", "bad array length");
return false;
}
@@ -347,7 +345,7 @@
};
int register_InstanceNonce(JNIEnv *env) {
- return jniRegisterNativeMethods(
+ return registerJniMethods(
env, "android/jni/cts/InstanceNonce",
methods, sizeof(methods) / sizeof(JNINativeMethod));
}
diff --git a/tests/tests/jni/libjnitest/android_jni_cts_JniCTest.c b/tests/tests/jni/libjnitest/android_jni_cts_JniCTest.c
index cca5383..4b2e294 100644
--- a/tests/tests/jni/libjnitest/android_jni_cts_JniCTest.c
+++ b/tests/tests/jni/libjnitest/android_jni_cts_JniCTest.c
@@ -19,7 +19,6 @@
*/
#include <jni.h>
-#include <nativehelper/JNIHelp.h>
/*
@@ -42,7 +41,7 @@
};
int register_JniCTest(JNIEnv *env) {
- return jniRegisterNativeMethods(
+ return registerJniMethods(
env, "android/jni/cts/JniCTest",
methods, sizeof(methods) / sizeof(JNINativeMethod));
}
diff --git a/tests/tests/jni/libjnitest/android_jni_cts_JniCppTest.cpp b/tests/tests/jni/libjnitest/android_jni_cts_JniCppTest.cpp
index b0937f41..df619be 100644
--- a/tests/tests/jni/libjnitest/android_jni_cts_JniCppTest.cpp
+++ b/tests/tests/jni/libjnitest/android_jni_cts_JniCppTest.cpp
@@ -19,7 +19,6 @@
*/
#include <jni.h>
-#include <nativehelper/JNIHelp.h>
/*
@@ -42,7 +41,7 @@
};
extern "C" int register_JniCppTest(JNIEnv *env) {
- return jniRegisterNativeMethods(
+ return registerJniMethods(
env, "android/jni/cts/JniCppTest",
methods, sizeof(methods) / sizeof(JNINativeMethod));
}
diff --git a/tests/tests/jni/libjnitest/android_jni_cts_JniStaticTest.cpp b/tests/tests/jni/libjnitest/android_jni_cts_JniStaticTest.cpp
index aa5651f..7aa54e2 100644
--- a/tests/tests/jni/libjnitest/android_jni_cts_JniStaticTest.cpp
+++ b/tests/tests/jni/libjnitest/android_jni_cts_JniStaticTest.cpp
@@ -19,7 +19,6 @@
*/
#include <jni.h>
-#include <nativehelper/JNIHelp.h>
extern "C" JNIEXPORT jint JNICALL Java_android_jni_cts_ClassLoaderHelper_nativeGetHashCode(
JNIEnv* env,
diff --git a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
index 2bd24b4..3128648 100644
--- a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
+++ b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
@@ -20,10 +20,12 @@
#include <dirent.h>
#include <dlfcn.h>
+#include <errno.h>
#include <fcntl.h>
#include <jni.h>
#include <libgen.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -37,9 +39,8 @@
#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedLocalRef.h>
-#include <nativehelper/ScopedUtfChars.h>
+#include <nativehelper/scoped_local_ref.h>
+#include <nativehelper/scoped_utf_chars.h>
#if defined(__LP64__)
#define LIB_DIR "lib64"
diff --git a/tests/tests/jni/libjnitest/android_jni_cts_StaticNonce.c b/tests/tests/jni/libjnitest/android_jni_cts_StaticNonce.c
index 4e330e5..7fb7f11 100644
--- a/tests/tests/jni/libjnitest/android_jni_cts_StaticNonce.c
+++ b/tests/tests/jni/libjnitest/android_jni_cts_StaticNonce.c
@@ -20,11 +20,12 @@
*/
#include <jni.h>
-#include <nativehelper/JNIHelp.h>
#include <stdbool.h>
#include <string.h>
+#include "helper.h"
+
// public static native void nop();
static void StaticNonce_nop(JNIEnv *env, jclass clazz) {
// This space intentionally left blank.
@@ -106,7 +107,7 @@
}
if (stringClass == NULL) {
- jniThrowException(env, "java/lang/AssertionError",
+ throwException(env, "java/lang/AssertionError",
"class String not found");
return NULL;
}
@@ -149,7 +150,7 @@
}
if (id == NULL) {
- jniThrowException(env, "java/lang/AssertionError",
+ throwException(env, "java/lang/AssertionError",
"constructor not found");
return NULL;
}
@@ -251,7 +252,7 @@
length = (*env)->GetStringUTFLength(env, v6);
if (length != 3) {
- jniThrowException(env, "java/lang/AssertionError",
+ throwException(env, "java/lang/AssertionError",
"bad string length");
return false;
}
@@ -267,7 +268,7 @@
length = (*env)->GetArrayLength(env, v9);
if (length != 2) {
- jniThrowException(env, "java/lang/AssertionError",
+ throwException(env, "java/lang/AssertionError",
"bad array length");
return false;
}
@@ -362,7 +363,7 @@
};
int register_StaticNonce(JNIEnv *env) {
- return jniRegisterNativeMethods(
+ return registerJniMethods(
env, "android/jni/cts/StaticNonce",
methods, sizeof(methods) / sizeof(JNINativeMethod));
}
diff --git a/tests/tests/jni/libjnitest/helper.c b/tests/tests/jni/libjnitest/helper.c
index 2281795..cf45911 100644
--- a/tests/tests/jni/libjnitest/helper.c
+++ b/tests/tests/jni/libjnitest/helper.c
@@ -87,3 +87,30 @@
return result;
}
+
+int registerJniMethods(JNIEnv* env, const char* className, const JNINativeMethod* methods,
+ int numMethods)
+{
+ __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG,
+ "Registering %s's %d native methods...", className, numMethods);
+ jclass clazz = (*env)->FindClass(env, className);
+ int result = (*env)->RegisterNatives(env, clazz, methods, numMethods);
+ (*env)->DeleteLocalRef(env, clazz);
+ if (result == 0) {
+ return 0;
+ }
+
+ __android_log_print(ANDROID_LOG_FATAL, LOG_TAG,
+ "Failed to register JNI methods for %s: %d\n", className, result);
+ return result;
+}
+
+void throwException(JNIEnv* env, const char* className, const char* message) {
+ jclass clazz = (*env)->FindClass(env, className);
+ int result = (*env)->ThrowNew(env, clazz, message);
+ if (result != 0) {
+ __android_log_print(ANDROID_LOG_FATAL, LOG_TAG,
+ "Failed to throw %s: d\n", className, result);
+
+ }
+}
diff --git a/tests/tests/jni/libjnitest/helper.h b/tests/tests/jni/libjnitest/helper.h
index f811055..69965fc 100644
--- a/tests/tests/jni/libjnitest/helper.h
+++ b/tests/tests/jni/libjnitest/helper.h
@@ -60,6 +60,26 @@
*/
char *runJniTests(JNIEnv *env, ...);
+/**
+ * Register JNI native methods.
+ *
+ * @param env the JNI environment
+ * @param className the class registering native methods
+ * @param methods an array of methods
+ * @param numMethods the number of methods in the array
+ */
+int registerJniMethods(JNIEnv* env, const char* className, const JNINativeMethod* methods,
+ int numMethods);
+
+/**
+ * Constructs an exception of the specified class name with the provided message.
+ *
+ * @param env the JNI environment
+ * @param className the class of the exception to construct
+ * @param message the message associated with the constructed exception
+ */
+void throwException(JNIEnv* env, const char* className, const char* message);
+
#ifdef __cplusplus
}
#endif
diff --git a/tests/tests/jni/src/android/jni/cts/LinkerNamespacesHelper.java b/tests/tests/jni/src/android/jni/cts/LinkerNamespacesHelper.java
index 6cd2441..0cab14b 100644
--- a/tests/tests/jni/src/android/jni/cts/LinkerNamespacesHelper.java
+++ b/tests/tests/jni/src/android/jni/cts/LinkerNamespacesHelper.java
@@ -82,7 +82,8 @@
private final static String[] PUBLIC_ART_LIBRARIES = {
"libicui18n.so",
"libicuuc.so",
- "libnativehelper.so"
+ "libnativehelper.so",
+ "libsigchain.so"
};
// The grey-list.
diff --git a/tests/tests/keystore/src/android/keystore/cts/CipherTest.java b/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
index c3a63f3..f1d7992 100644
--- a/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
@@ -29,6 +29,8 @@
import com.google.common.collect.ObjectArrays;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.security.AlgorithmParameters;
import java.security.InvalidKeyException;
import java.security.Key;
@@ -44,11 +46,14 @@
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
+import java.util.Random;
import java.util.Set;
import java.util.TreeMap;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
@@ -90,6 +95,13 @@
private static String[] EXPECTED_ALGORITHMS = BASE_EXPECTED_ALGORITHMS;
+ // For tests of behavior largely unrelated to the selected algorithm, such as
+ // unlockedDeviceRequired
+ private static final String[] BASIC_ALGORITHMS = {
+ "AES/GCM/NoPadding",
+ "RSA/ECB/OAEPWithSHA-256AndMGF1Padding",
+ };
+
static {
if (TestUtils.supports3DES()) {
EXPECTED_ALGORITHMS = ObjectArrays
@@ -281,6 +293,7 @@
public void performDeviceUnlock() throws Exception {
mLockCredential.gotoKeyguard();
+ SystemClock.sleep(200);
mLockCredential.enterAndConfirmLockCredential();
launchHomeActivity();
KeyguardManager keyguardManager = (KeyguardManager)getContext().getSystemService(
@@ -483,6 +496,79 @@
}
}
+ /*
+ * This test performs a round trip en/decryption using Cipher*Streams.
+ */
+ public void testEncryptsAndDecryptsUsingCipherStreams()
+ throws Exception {
+
+ Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME);
+ assertNotNull(provider);
+ final byte[] originalPlaintext = new byte[1024];
+ new Random().nextBytes(originalPlaintext);
+ for (String algorithm : EXPECTED_ALGORITHMS) {
+ for (ImportedKey key : importKatKeys(
+ algorithm,
+ KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT,
+ false)) {
+ try {
+ Key encryptionKey = key.getKeystoreBackedEncryptionKey();
+ byte[] plaintext = truncatePlaintextIfNecessary(
+ algorithm, encryptionKey, originalPlaintext);
+ if (plaintext == null) {
+ // Key is too short to encrypt anything using this transformation
+ continue;
+ }
+ Cipher cipher = Cipher.getInstance(algorithm, provider);
+ cipher.init(Cipher.ENCRYPT_MODE, encryptionKey);
+ final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ final CipherOutputStream cipherOutputStream =
+ new CipherOutputStream(byteArrayOutputStream, cipher);
+
+ cipherOutputStream.write(plaintext);
+ cipherOutputStream.close();
+ AlgorithmParameters params = cipher.getParameters();
+ byte[] expectedPlaintext = plaintext;
+ if ("RSA/ECB/NoPadding".equalsIgnoreCase(algorithm)) {
+ // RSA decryption without padding left-pads resulting plaintext with NUL
+ // bytes to the length of RSA modulus.
+ int modulusLengthBytes = (TestUtils.getKeySizeBits(encryptionKey) + 7) / 8;
+ expectedPlaintext = TestUtils.leftPadWithZeroBytes(
+ expectedPlaintext, modulusLengthBytes);
+ }
+
+ byte[] ciphertext = byteArrayOutputStream.toByteArray();
+ assertNotNull(ciphertext);
+ cipher = Cipher.getInstance(algorithm, provider);
+ Key decryptionKey = key.getKeystoreBackedDecryptionKey();
+ cipher.init(Cipher.DECRYPT_MODE, decryptionKey, params);
+
+ final ByteArrayInputStream byteArrayInputStream =
+ new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
+ final CipherInputStream cipherInputStream =
+ new CipherInputStream(byteArrayInputStream, cipher);
+ byte[] actualPlaintext = new byte[plaintext.length * 2];
+ int total = 0;
+ int count = 0;
+ while((count = cipherInputStream.read(actualPlaintext, total,
+ actualPlaintext.length - total)) != -1) {
+ total += count;
+ }
+ actualPlaintext = Arrays.copyOf(actualPlaintext, total);
+ cipherInputStream.close();
+ assertTrue("expected(" + expectedPlaintext.length + "): "
+ + HexEncoding.encode(expectedPlaintext)
+ + "\nactual(" + actualPlaintext.length + "): "
+ + HexEncoding.encode(actualPlaintext),
+ Arrays.equals(expectedPlaintext, actualPlaintext));
+ } catch (Throwable e) {
+ throw new RuntimeException(
+ "Failed for " + algorithm + " with key " + key.getAlias(),
+ e);
+ }
+ }
+ }
+ }
private boolean isDecryptValid(byte[] expectedPlaintext, byte[] ciphertext, Cipher cipher,
AlgorithmParameters params, ImportedKey key) {
@@ -531,25 +617,37 @@
}
try (DeviceLockSession dl = new DeviceLockSession()) {
+ dl.performDeviceLock();
KeyguardManager keyguardManager = (KeyguardManager)getContext()
.getSystemService(Context.KEYGUARD_SERVICE);
Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME);
assertNotNull(provider);
final byte[] originalPlaintext = EmptyArray.BYTE;
- for (String algorithm : EXPECTED_ALGORITHMS) {
- // Normally we would test all combinations of algorithms and key sizes, but the
- // semi-manual locking and unlocking this requires takes way too long if we try to
- // go through all of those. Other tests check all the key sizes, so we don't need to
- // duplicate all that work.
- for (ImportedKey key : importKatKeys(
- algorithm,
- KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT,
- false, isUnlockedDeviceRequired, isUserAuthRequired)) {
+ // Normally we would test all combinations of algorithms and key sizes, but the
+ // semi-manual locking and unlocking this requires takes way too long if we try to
+ // go through all of those. Other tests check all the key sizes, so we don't need to
+ // duplicate all that work.
+ for (String algorithm : BASIC_ALGORITHMS) {
+ for (boolean createWhileLocked : new boolean[]{false, true}) {
try {
+ if (createWhileLocked) {
+ dl.performDeviceLock();
+ } else {
+ dl.performDeviceUnlock();
+ }
+ // Test just a single key in the collection
+ ImportedKey key = importKatKeys(
+ algorithm,
+ KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT,
+ false, isUnlockedDeviceRequired,
+ isUserAuthRequired).iterator().next();
+ if (createWhileLocked) {
+ dl.performDeviceUnlock();
+ }
Key encryptionKey = key.getKeystoreBackedEncryptionKey();
byte[] plaintext = truncatePlaintextIfNecessary(
- algorithm, encryptionKey, originalPlaintext);
+ algorithm, encryptionKey, originalPlaintext);
if (plaintext == null) {
// Key is too short to encrypt anything using this transformation
continue;
@@ -561,32 +659,39 @@
byte[] ciphertext = cipher.doFinal(plaintext);
byte[] expectedPlaintext = plaintext;
if ("RSA/ECB/NoPadding".equalsIgnoreCase(algorithm)) {
- // RSA decryption without padding left-pads resulting plaintext with NUL
- // bytes to the length of RSA modulus.
- int modulusLengthBytes = (TestUtils.getKeySizeBits(encryptionKey) + 7) / 8;
+ // RSA decryption without padding left-pads resulting plaintext
+ // with NUL bytes to the length of RSA modulus.
+ int modulusLengthBytes = (TestUtils.getKeySizeBits(encryptionKey)
+ + 7) / 8;
expectedPlaintext = TestUtils.leftPadWithZeroBytes(
- expectedPlaintext, modulusLengthBytes);
+ expectedPlaintext, modulusLengthBytes);
}
dl.performDeviceLock();
// Attempt to decrypt the data with the device locked.
cipher = Cipher.getInstance(algorithm, provider);
- assertFalse(isDecryptValid(expectedPlaintext, ciphertext, cipher, params, key));
+ assertFalse(
+ isDecryptValid(expectedPlaintext, ciphertext, cipher, params,
+ key));
// Then attempt to decrypt the data with the device unlocked
// This should succeed
dl.performDeviceUnlock();
cipher = Cipher.getInstance(algorithm, provider);
- assertTrue(isDecryptValid(expectedPlaintext, ciphertext, cipher, params, key));
+ assertTrue(isDecryptValid(expectedPlaintext, ciphertext, cipher, params,
+ key));
+
+ // Ensure a second decryption also succeeds
+ cipher = Cipher.getInstance(algorithm, provider);
+ assertTrue(isDecryptValid(expectedPlaintext, ciphertext, cipher, params,
+ key));
} catch (Throwable e) {
throw new RuntimeException(
- "Failed for " + algorithm + " with key " + key.getAlias(),
- e);
+ "Failed on createWhileLocked " + createWhileLocked + " for " +
+ algorithm,
+ e);
}
- // We don't know the underlying type of this collection, so just break out of
- // the iterator loop.
- break;
}
}
}
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAgreementTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAgreementTest.java
index 85e24b3..c8d0eae 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAgreementTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAgreementTest.java
@@ -18,10 +18,12 @@
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
+import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
+import java.security.spec.InvalidKeySpecException;
import javax.crypto.KeyAgreement;
@@ -29,8 +31,11 @@
import org.junit.Assert;
+import android.content.Context;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyInfo;
+import androidx.test.InstrumentationRegistry;
public class KeyAgreementTest extends TestCase {
private static final String PRIVATE_KEY_ALIAS = "TemporaryPrivateKey";
@@ -92,6 +97,22 @@
}
}
+ public void testInit_withNonEcKey_fails() throws Exception {
+ KeyPairGenerator kpg =
+ KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
+ kpg.initialize(
+ new KeyGenParameterSpec.Builder("rsakey", KeyProperties.PURPOSE_AGREE_KEY).build());
+ KeyPair rsaKeyPair = kpg.genKeyPair();
+ KeyAgreement ka = getKeyStoreKeyAgreement();
+
+ try {
+ ka.init(rsaKeyPair.getPrivate());
+ fail("Initializing KeyAgreement with non-EC key should fail.");
+ } catch (InvalidKeyException ike) {
+ // Expected
+ }
+ }
+
public void testDoPhase_withoutInitialization_fails() throws Exception {
KeyAgreement ka = getKeyStoreKeyAgreement();
try {
@@ -139,7 +160,31 @@
kpg.initialize(
new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_AGREE_KEY).build());
- return kpg.generateKeyPair();
+ KeyPair kp = kpg.generateKeyPair();
+
+ KeyFactory factory = KeyFactory.getInstance(kp.getPrivate().getAlgorithm(),
+ "AndroidKeyStore");
+ KeyInfo keyInfo = null;
+ try {
+ keyInfo = factory.getKeySpec(kp.getPrivate(), KeyInfo.class);
+ } catch (InvalidKeySpecException e) {
+ // Not an Android KeyStore key.
+ fail("Unable to get KeyInfo for created key.");
+ }
+
+ // ECDH is only implemented in Secure Hardware if KeyMint is available.
+ int level = keyInfo.getSecurityLevel();
+ Context context = InstrumentationRegistry.getTargetContext();
+ if (TestUtils.getFeatureVersionKeystore(context) >= Attestation.KM_VERSION_KEYMINT_1) {
+ Assert.assertTrue(
+ level == KeyProperties.SECURITY_LEVEL_TRUSTED_ENVIRONMENT ||
+ level == KeyProperties.SECURITY_LEVEL_UNKNOWN_SECURE);
+ } else {
+ Assert.assertEquals(keyInfo.getSecurityLevel(),
+ KeyProperties.SECURITY_LEVEL_SOFTWARE);
+ }
+
+ return kp;
}
private static KeyPair generateEphemeralServerKeyPair() throws GeneralSecurityException {
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 596d391..0c022e3 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -54,6 +54,7 @@
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.lessThanOrEqualTo;
+import static org.junit.Assert.assertNotEquals;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -299,6 +300,103 @@
}
}
+ public void testAttestationKmVersionMatchesFeatureVersion() throws Exception {
+ if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
+ return;
+
+ String keystoreAlias = "test_key";
+ Date now = new Date();
+ Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET);
+ Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET);
+ KeyGenParameterSpec.Builder builder =
+ new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
+ .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
+ .setAttestationChallenge(new byte[128])
+ .setKeyValidityStart(now)
+ .setKeyValidityForOriginationEnd(originationEnd)
+ .setKeyValidityForConsumptionEnd(consumptionEnd);
+
+ generateKeyPair(KEY_ALGORITHM_EC, builder.build());
+
+ KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ keyStore.load(null);
+
+ try {
+ Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
+ verifyCertificateChain(certificates, false /* expectStrongBox */);
+ X509Certificate attestationCert = (X509Certificate) certificates[0];
+ Attestation attestation = Attestation.loadFromCertificate(attestationCert);
+ int kmVersionFromAttestation = attestation.keymasterVersion;
+ int keyStoreFeatureVersion = TestUtils.getFeatureVersionKeystore(getContext());
+
+ // Feature Version is required on devices launching with Android 12 (API Level
+ // 31) but may be reported on devices launching with an earlier version. If it's
+ // present, it must match what is reported in attestation.
+ int firstApiLevel = SystemProperties.getInt("ro.product.first_api_level", 0);
+ if (firstApiLevel >= 31) {
+ assertNotEquals(0, keyStoreFeatureVersion);
+ }
+ if (keyStoreFeatureVersion != 0) {
+ assertEquals(kmVersionFromAttestation, keyStoreFeatureVersion);
+ }
+ } finally {
+ keyStore.deleteEntry(keystoreAlias);
+ }
+ }
+
+ public void testAttestationKmVersionMatchesFeatureVersionStrongBox() throws Exception {
+ if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
+ return;
+
+ int keyStoreFeatureVersionStrongBox =
+ TestUtils.getFeatureVersionKeystoreStrongBox(getContext());
+
+ if (!TestUtils.hasStrongBox(getContext())) {
+ // If there's no StrongBox, ensure there's no feature version for it.
+ assertEquals(0, keyStoreFeatureVersionStrongBox);
+ return;
+ }
+
+ String keystoreAlias = "test_key";
+ Date now = new Date();
+ Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET);
+ Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET);
+ KeyGenParameterSpec.Builder builder =
+ new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
+ .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
+ .setAttestationChallenge(new byte[128])
+ .setKeyValidityStart(now)
+ .setKeyValidityForOriginationEnd(originationEnd)
+ .setKeyValidityForConsumptionEnd(consumptionEnd)
+ .setIsStrongBoxBacked(true);
+
+ generateKeyPair(KEY_ALGORITHM_EC, builder.build());
+
+ KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ keyStore.load(null);
+
+ try {
+ Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
+ verifyCertificateChain(certificates, true /* expectStrongBox */);
+ X509Certificate attestationCert = (X509Certificate) certificates[0];
+ Attestation attestation = Attestation.loadFromCertificate(attestationCert);
+ int kmVersionFromAttestation = attestation.keymasterVersion;
+
+ // Feature Version is required on devices launching with Android 12 (API Level
+ // 31) but may be reported on devices launching with an earlier version. If it's
+ // present, it must match what is reported in attestation.
+ int firstApiLevel = SystemProperties.getInt("ro.product.first_api_level", 0);
+ if (firstApiLevel >= 31) {
+ assertNotEquals(0, keyStoreFeatureVersionStrongBox);
+ }
+ if (keyStoreFeatureVersionStrongBox != 0) {
+ assertEquals(kmVersionFromAttestation, keyStoreFeatureVersionStrongBox);
+ }
+ } finally {
+ keyStore.deleteEntry(keystoreAlias);
+ }
+ }
+
public void testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId() throws Exception {
String keystoreAlias = "test_key";
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
@@ -956,8 +1054,9 @@
@SuppressWarnings("unchecked")
private void checkAttestationSecurityLevelDependentParams(Attestation attestation) {
- assertThat("Attestation version must be 1, 2, 3, 4 or 5", attestation.getAttestationVersion(),
- either(is(1)).or(is(2)).or(is(3)).or(is(4)).or(is(5)));
+ assertThat("Attestation version must be 1, 2, 3, 4 or 100",
+ attestation.getAttestationVersion(),
+ either(is(1)).or(is(2)).or(is(3)).or(is(4)).or(is(100)));
AuthorizationList teeEnforced = attestation.getTeeEnforced();
AuthorizationList softwareEnforced = attestation.getSoftwareEnforced();
@@ -971,7 +1070,7 @@
attestation.getKeymasterSecurityLevel(),
is(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT));
assertThat(attestation.getKeymasterVersion(),
- either(is(2)).or(is(3)).or(is(4)).or(is(41)));
+ either(is(2)).or(is(3)).or(is(4)).or(is(41)).or(is(100)));
checkRootOfTrust(attestation, false /* requireLocked */);
assertThat(teeEnforced.getOsVersion(), is(systemOsVersion));
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java
index 431ffa5..6d9b33a 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java
@@ -83,6 +83,7 @@
}
static final int[] AES_SUPPORTED_KEY_SIZES = new int[] {128, 192, 256};
+ static final int[] AES_STRONGBOX_SUPPORTED_KEY_SIZES = new int[] {128, 256};
static final int[] DES_SUPPORTED_KEY_SIZES = new int[] {168};
public void testAlgorithmList() {
@@ -277,13 +278,17 @@
}
}
rng.resetCounters();
- if (TestUtils.contains(AES_SUPPORTED_KEY_SIZES, i)) {
+ if (TestUtils.contains(useStrongbox ?
+ AES_STRONGBOX_SUPPORTED_KEY_SIZES : AES_SUPPORTED_KEY_SIZES, i)) {
keyGenerator.init(spec, rng);
SecretKey key = keyGenerator.generateKey();
assertEquals(i, TestUtils.getKeyInfo(key).getKeySize());
assertEquals((i + 7) / 8, rng.getOutputSizeBytes());
} else {
try {
+ if (useStrongbox && (i == 192))
+ throw new InvalidAlgorithmParameterException("Strongbox does not"
+ + " support key size 192.");
keyGenerator.init(spec, rng);
fail();
} catch (InvalidAlgorithmParameterException expected) {}
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java
index 7bdccb7..5eac878 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java
@@ -882,7 +882,6 @@
.setCertificateSubject(certSubject)
.setCertificateNotBefore(certNotBefore)
.setCertificateNotAfter(certNotAfter)
- .setUnlockedDeviceRequired(true)
.build());
KeyPair keyPair = generator.generateKeyPair();
assertGeneratedKeyPairAndSelfSignedCertificate(
@@ -952,7 +951,6 @@
.setCertificateSubject(certSubject)
.setCertificateNotBefore(certNotBefore)
.setCertificateNotAfter(certNotAfter)
- .setUnlockedDeviceRequired(true)
.setIsStrongBoxBacked(true)
.build());
KeyPair keyPair = generator.generateKeyPair();
@@ -1023,7 +1021,6 @@
.setCertificateSubject(certSubject)
.setCertificateNotBefore(certNotBefore)
.setCertificateNotAfter(certNotAfter)
- .setUnlockedDeviceRequired(true)
.build());
KeyPair keyPair = generator.generateKeyPair();
assertGeneratedKeyPairAndSelfSignedCertificate(
@@ -1097,7 +1094,7 @@
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY
| KeyProperties.PURPOSE_ENCRYPT)
.setAlgorithmParameterSpec(
- new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F0))
+ new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4))
.setKeySize(2048)
.setDigests(KeyProperties.DIGEST_SHA256)
.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS,
@@ -1112,7 +1109,6 @@
.setCertificateSubject(certSubject)
.setCertificateNotBefore(certNotBefore)
.setCertificateNotAfter(certNotAfter)
- .setUnlockedDeviceRequired(true)
.setIsStrongBoxBacked(true)
.build());
KeyPair keyPair = generator.generateKeyPair();
@@ -1125,7 +1121,7 @@
certSerialNumber,
certNotBefore,
certNotAfter);
- assertEquals(RSAKeyGenParameterSpec.F0,
+ assertEquals(RSAKeyGenParameterSpec.F4,
((RSAPublicKey) keyPair.getPublic()).getPublicExponent());
KeyInfo keyInfo = TestUtils.getKeyInfo(keyPair.getPrivate());
assertEquals(2048, keyInfo.getKeySize());
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyStoreTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyStoreTest.java
index ab9cec7..383e483 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyStoreTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyStoreTest.java
@@ -815,20 +815,15 @@
try {
keyStore.setKeyEntry(null, null, null, null);
fail(keyStore.getType());
- } catch (Exception e) {
- if (e.getClass() != NullPointerException.class
- && e.getClass() != KeyStoreException.class) {
- throw e;
- }
+ } catch (NullPointerException | KeyStoreException expected) {
+ // ignored
}
+
try {
keyStore.setKeyEntry(null, null, PASSWORD_KEY, null);
fail(keyStore.getType());
- } catch (Exception e) {
- if (e.getClass() != NullPointerException.class
- && e.getClass() != KeyStoreException.class) {
- throw e;
- }
+ } catch (NullPointerException | KeyStoreException expected) {
+ // ignored
}
try {
keyStore.setKeyEntry(ALIAS_PRIVATE,
diff --git a/tests/tests/keystore/src/android/keystore/cts/TestUtils.java b/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
index 3e9d7d0..aeb3ad6 100644
--- a/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
+++ b/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.pm.FeatureInfo;
import android.os.SystemProperties;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyInfo;
@@ -82,6 +83,54 @@
private TestUtils() {}
+ // Returns 0 if not implemented. Otherwise returns the feature version.
+ //
+ static int getFeatureVersionKeystore(Context appContext) {
+ PackageManager pm = appContext.getPackageManager();
+
+ int featureVersionFromPm = 0;
+ if (pm.hasSystemFeature(PackageManager.FEATURE_HARDWARE_KEYSTORE)) {
+ FeatureInfo info = null;
+ FeatureInfo[] infos = pm.getSystemAvailableFeatures();
+ for (int n = 0; n < infos.length; n++) {
+ FeatureInfo i = infos[n];
+ if (i.name.equals(PackageManager.FEATURE_HARDWARE_KEYSTORE)) {
+ info = i;
+ break;
+ }
+ }
+ if (info != null) {
+ featureVersionFromPm = info.version;
+ }
+ }
+
+ return featureVersionFromPm;
+ }
+
+ // Returns 0 if not implemented. Otherwise returns the feature version.
+ //
+ static int getFeatureVersionKeystoreStrongBox(Context appContext) {
+ PackageManager pm = appContext.getPackageManager();
+
+ int featureVersionFromPm = 0;
+ if (pm.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE)) {
+ FeatureInfo info = null;
+ FeatureInfo[] infos = pm.getSystemAvailableFeatures();
+ for (int n = 0; n < infos.length; n++) {
+ FeatureInfo i = infos[n];
+ if (i.name.equals(PackageManager.FEATURE_STRONGBOX_KEYSTORE)) {
+ info = i;
+ break;
+ }
+ }
+ if (info != null) {
+ featureVersionFromPm = info.version;
+ }
+ }
+
+ return featureVersionFromPm;
+ }
+
/**
* Returns whether 3DES KeyStore tests should run on this device. 3DES support was added in
* KeyMaster 4.0 and there should be no software fallback on earlier KeyMaster versions.
diff --git a/tests/tests/libnativehelper/OWNERS b/tests/tests/libnativehelper/OWNERS
index da3f4a8..8d9029d 100644
--- a/tests/tests/libnativehelper/OWNERS
+++ b/tests/tests/libnativehelper/OWNERS
@@ -1,5 +1,4 @@
# Bug component: 86431
-enh@google.com
mast@google.com
ngeoffray@google.com
oth@google.com
diff --git a/tests/tests/libnativehelper/jni/file_descriptor_ndk_test.cpp b/tests/tests/libnativehelper/jni/file_descriptor_ndk_test.cpp
index 6df63cf..459c359 100644
--- a/tests/tests/libnativehelper/jni/file_descriptor_ndk_test.cpp
+++ b/tests/tests/libnativehelper/jni/file_descriptor_ndk_test.cpp
@@ -23,13 +23,13 @@
jobject jifd = AFileDescriptor_create(mEnv);
ASSERT_NE(nullptr, jifd);
ASSERT_EQ(JNI_FALSE, mEnv->ExceptionCheck());
- ASSERT_EQ(kInvalidFd, AFileDescriptor_getFD(mEnv, jifd));
+ ASSERT_EQ(kInvalidFd, AFileDescriptor_getFd(mEnv, jifd));
static const int kSubsequentUnixFds[] = { 0, -1, -999, -1, 0, 1812, -1, 1066 };
for (int unixFd : kSubsequentUnixFds) {
- AFileDescriptor_setFD(mEnv, jifd, unixFd);
+ AFileDescriptor_setFd(mEnv, jifd, unixFd);
ASSERT_EQ(JNI_FALSE, mEnv->ExceptionCheck());
- ASSERT_EQ(unixFd, AFileDescriptor_getFD(mEnv, jifd));
+ ASSERT_EQ(unixFd, AFileDescriptor_getFd(mEnv, jifd));
ASSERT_EQ(JNI_FALSE, mEnv->ExceptionCheck());
}
}
diff --git a/tests/tests/media/res/raw/sample_mpegh_mha1.mp4 b/tests/tests/media/res/raw/sample_mpegh_mha1.mp4
new file mode 100644
index 0000000..23a211c
--- /dev/null
+++ b/tests/tests/media/res/raw/sample_mpegh_mha1.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/sample_mpegh_mhm1.mp4 b/tests/tests/media/res/raw/sample_mpegh_mhm1.mp4
new file mode 100644
index 0000000..25ea55b
--- /dev/null
+++ b/tests/tests/media/res/raw/sample_mpegh_mhm1.mp4
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/AudioFormatTest.java b/tests/tests/media/src/android/media/cts/AudioFormatTest.java
index af5e572..e7b59a3 100644
--- a/tests/tests/media/src/android/media/cts/AudioFormatTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioFormatTest.java
@@ -182,7 +182,13 @@
AudioFormat.ENCODING_AAC_LC,
AudioFormat.ENCODING_AAC_HE_V1,
AudioFormat.ENCODING_AAC_HE_V2,
- AudioFormat.ENCODING_OPUS
+ AudioFormat.ENCODING_OPUS,
+ AudioFormat.ENCODING_MPEGH_BL_L3,
+ AudioFormat.ENCODING_MPEGH_BL_L4,
+ AudioFormat.ENCODING_MPEGH_LC_L3,
+ AudioFormat.ENCODING_MPEGH_LC_L4,
+ AudioFormat.ENCODING_DTS_UHD,
+ AudioFormat.ENCODING_DRA,
};
for (int encoding : encodings) {
final AudioFormat format = new AudioFormat.Builder()
@@ -204,4 +210,65 @@
assertEquals("Float AudioFormat has the wrong frame size",
2 /* channels */ * 4 /* bytes per sample */, formatPcmFloat.getFrameSizeInBytes());
}
+
+ /**
+ * Check whether the bits in a are all present in b.
+ *
+ * Used for channel position mask verification.
+ */
+ private boolean subsetOf(int a, int b) {
+ return Integer.bitCount(a ^ b) == Integer.bitCount(b) - Integer.bitCount(a);
+ }
+
+ /**
+ * Test case 8: Check validity of channel masks
+ */
+ public void testChannelMasks() throws Exception {
+ // Channel count check.
+ int[][] maskCount = new int[][] {
+ {AudioFormat.CHANNEL_OUT_MONO, 1},
+ {AudioFormat.CHANNEL_OUT_STEREO, 2},
+ {AudioFormat.CHANNEL_OUT_QUAD, 4},
+ {AudioFormat.CHANNEL_OUT_SURROUND, 4},
+ {AudioFormat.CHANNEL_OUT_5POINT1, 6},
+ {AudioFormat.CHANNEL_OUT_5POINT1POINT2, 8},
+ {AudioFormat.CHANNEL_OUT_7POINT1_SURROUND, 8},
+ {AudioFormat.CHANNEL_OUT_5POINT1POINT4, 10},
+ {AudioFormat.CHANNEL_OUT_7POINT1POINT2, 10},
+ {AudioFormat.CHANNEL_OUT_7POINT1POINT4, 12},
+ {AudioFormat.CHANNEL_OUT_13POINT_360RA, 13},
+ {AudioFormat.CHANNEL_OUT_22POINT2, 24},
+ };
+ for (int[] pair : maskCount) {
+ assertEquals("Mask " + Integer.toHexString(pair[0])
+ + " should have " + pair[1] + " bits set",
+ Integer.bitCount(pair[0]), pair[1]);
+ }
+
+ // Check channel position masks that are a subset of other masks.
+ assertTrue(subsetOf(AudioFormat.CHANNEL_OUT_MONO,
+ AudioFormat.CHANNEL_OUT_STEREO));
+ assertTrue(subsetOf(AudioFormat.CHANNEL_OUT_STEREO,
+ AudioFormat.CHANNEL_OUT_QUAD));
+ assertTrue(subsetOf(AudioFormat.CHANNEL_OUT_STEREO,
+ AudioFormat.CHANNEL_OUT_SURROUND));
+ assertTrue(subsetOf(AudioFormat.CHANNEL_OUT_QUAD,
+ AudioFormat.CHANNEL_OUT_5POINT1));
+ assertTrue(subsetOf(AudioFormat.CHANNEL_OUT_5POINT1,
+ AudioFormat.CHANNEL_OUT_5POINT1POINT2));
+ assertTrue(subsetOf(AudioFormat.CHANNEL_OUT_5POINT1,
+ AudioFormat.CHANNEL_OUT_5POINT1POINT4));
+ // Note CHANNEL_OUT_5POINT1POINT2 not a subset of CHANNEL_OUT_5POINT1POINT4
+ assertTrue(subsetOf(AudioFormat.CHANNEL_OUT_7POINT1_SURROUND,
+ AudioFormat.CHANNEL_OUT_7POINT1POINT2));
+ assertTrue(subsetOf(AudioFormat.CHANNEL_OUT_7POINT1_SURROUND,
+ AudioFormat.CHANNEL_OUT_7POINT1POINT4));
+ // Note CHANNEL_OUT_7POINT1POINT2 not a subset of CHANNEL_OUT_7POINT1POINT4
+ assertTrue(subsetOf(AudioFormat.CHANNEL_OUT_5POINT1POINT4,
+ AudioFormat.CHANNEL_OUT_7POINT1POINT4));
+ assertTrue(subsetOf(AudioFormat.CHANNEL_OUT_7POINT1POINT4,
+ AudioFormat.CHANNEL_OUT_22POINT2));
+ assertTrue(subsetOf(AudioFormat.CHANNEL_OUT_13POINT_360RA,
+ AudioFormat.CHANNEL_OUT_22POINT2));
+ }
}
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordTest.java b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
index e14a6c5..f2ae7b4 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
@@ -385,6 +385,30 @@
AudioFormat.ENCODING_PCM_16BIT);
}
+ // Audit buffers can run out of space with high numbers of channels,
+ // so keep the sample rate low.
+ @Test
+ public void testAudioRecordAuditChannelIndex3() throws Exception {
+ doTest("audit_channel_index_3", true /*localRecord*/, true /*customHandler*/,
+ 2 /*periodsPerSecond*/, 0 /*markerPeriodsPerSecond*/,
+ true /*useByteBuffer*/, false /*blocking*/,
+ true /*auditRecording*/, true /*isChannelIndex*/, 16000 /*TEST_SR*/,
+ (1 << 0) | (1 << 1) | (1 << 2) /* 3 channels */,
+ AudioFormat.ENCODING_PCM_24BIT_PACKED);
+ }
+
+ // Audit buffers can run out of space with high numbers of channels,
+ // so keep the sample rate low.
+ @Test
+ public void testAudioRecordAuditChannelIndex1() throws Exception {
+ doTest("audit_channel_index_1", true /*localRecord*/, true /*customHandler*/,
+ 2 /*periodsPerSecond*/, 0 /*markerPeriodsPerSecond*/,
+ true /*useByteBuffer*/, false /*blocking*/,
+ true /*auditRecording*/, true /*isChannelIndex*/, 24000 /*TEST_SR*/,
+ (1 << 0) /* 1 channels */,
+ AudioFormat.ENCODING_PCM_32BIT);
+ }
+
// Test AudioRecord.Builder to verify the observed configuration of an AudioRecord built with
// an empty Builder matches the documentation / expected values
@Test
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
index 372b583..1dec098 100755
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -32,6 +32,7 @@
import android.media.AudioMetadata;
import android.media.AudioMetadataReadMap;
import android.media.AudioPresentation;
+import android.media.AudioSystem;
import android.media.AudioTimestamp;
import android.media.AudioTrack;
import android.media.PlaybackParams;
@@ -1855,6 +1856,117 @@
Thread.sleep(waitMsec); // wait for release to complete
}
+ private void playOnceStreamByteBuffer(
+ String testName, double testFrequency, double testSweep,
+ int testStreamType, int testSampleRate, int testChannelMask, int testEncoding,
+ int testTransferMode, int testWriteMode,
+ boolean useChannelIndex, boolean useDirect) throws Exception {
+ AudioTrack track = null;
+ try {
+ AudioFormat.Builder afb = new AudioFormat.Builder()
+ .setEncoding(testEncoding)
+ .setSampleRate(testSampleRate);
+ if (useChannelIndex) {
+ afb.setChannelIndexMask(testChannelMask);
+ } else {
+ afb.setChannelMask(testChannelMask);
+ }
+ final AudioFormat format = afb.build();
+ final int frameSize = AudioHelper.frameSizeFromFormat(format);
+ final int frameCount =
+ AudioHelper.frameCountFromMsec(300 /* ms */, format);
+ final int bufferSize = frameCount * frameSize;
+ final int bufferSamples = frameCount * format.getChannelCount();
+
+ track = new AudioTrack.Builder()
+ .setAudioFormat(format)
+ .setTransferMode(testTransferMode)
+ .setBufferSizeInBytes(bufferSize)
+ .build();
+
+ assertEquals(testName + ": state",
+ AudioTrack.STATE_INITIALIZED, track.getState());
+ assertEquals(testName + ": sample rate",
+ testSampleRate, track.getSampleRate());
+ assertEquals(testName + ": encoding",
+ testEncoding, track.getAudioFormat());
+
+ ByteBuffer bb = useDirect
+ ? ByteBuffer.allocateDirect(bufferSize)
+ : ByteBuffer.allocate(bufferSize);
+ bb.order(java.nio.ByteOrder.nativeOrder());
+
+ final double sampleFrequency = testFrequency / format.getChannelCount();
+ switch (testEncoding) {
+ case AudioFormat.ENCODING_PCM_8BIT: {
+ byte data[] = AudioHelper.createSoundDataInByteArray(
+ bufferSamples, testSampleRate,
+ sampleFrequency, testSweep);
+ bb.put(data);
+ bb.flip();
+ }
+ break;
+ case AudioFormat.ENCODING_PCM_16BIT: {
+ short data[] = AudioHelper.createSoundDataInShortArray(
+ bufferSamples, testSampleRate,
+ sampleFrequency, testSweep);
+ ShortBuffer sb = bb.asShortBuffer();
+ sb.put(data);
+ bb.limit(sb.limit() * 2);
+ }
+ break;
+ case AudioFormat.ENCODING_PCM_FLOAT: {
+ float data[] = AudioHelper.createSoundDataInFloatArray(
+ bufferSamples, testSampleRate,
+ sampleFrequency, testSweep);
+ FloatBuffer fb = bb.asFloatBuffer();
+ fb.put(data);
+ bb.limit(fb.limit() * 4);
+ }
+ break;
+ }
+ // start the AudioTrack
+ // This can be done before or after the first write.
+ // Current behavior for streaming tracks is that
+ // actual playback does not begin before the internal
+ // data buffer is completely full.
+ track.play();
+
+ // write data
+ final long startTime = System.currentTimeMillis();
+ final long maxDuration = frameCount * 1000 / testSampleRate + 1000;
+ for (int written = 0; written < bufferSize; ) {
+ // ret may return a short count if write
+ // is non blocking or even if write is blocking
+ // when a stop/pause/flush is issued from another thread.
+ final int kBatchFrames = 1000;
+ int ret = track.write(bb,
+ Math.min(bufferSize - written, frameSize * kBatchFrames),
+ testWriteMode);
+ // for non-blocking mode, this loop may spin quickly
+ assertTrue(testName + ": write error " + ret, ret >= 0);
+ assertTrue(testName + ": write timeout",
+ (System.currentTimeMillis() - startTime) <= maxDuration);
+ written += ret;
+ }
+
+ // for streaming tracks, stop will allow the rest of the data to
+ // drain out, but we don't know how long to wait unless
+ // we check the position before stop. if we check position
+ // after we stop, we read 0.
+ final int position = track.getPlaybackHeadPosition();
+ final int remainingTimeMs = (int)((double)(frameCount - position)
+ * 1000 / testSampleRate);
+ track.stop();
+ Thread.sleep(remainingTimeMs);
+ Thread.sleep(WAIT_MSEC);
+ } finally {
+ if (track != null) {
+ track.release();
+ }
+ }
+ }
+
@Test
public void testPlayStreamByteBuffer() throws Exception {
// constants for test
@@ -1876,7 +1988,7 @@
};
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
- final float TEST_SWEEP = 0; // sine wave only
+ final double TEST_SWEEP = 0; // sine wave only
for (int TEST_FORMAT : TEST_FORMAT_ARRAY) {
double frequency = 800; // frequency changes for each test
@@ -1884,76 +1996,14 @@
for (int TEST_CONF : TEST_CONF_ARRAY) {
for (int TEST_WRITE_MODE : TEST_WRITE_MODE_ARRAY) {
for (int useDirect = 0; useDirect < 2; ++useDirect) {
- // -------- initialization --------------
- int minBufferSize = AudioTrack.getMinBufferSize(TEST_SR,
- TEST_CONF, TEST_FORMAT); // in bytes
- int bufferSize = 12 * minBufferSize;
- int bufferSamples = bufferSize
- / AudioFormat.getBytesPerSample(TEST_FORMAT);
+ playOnceStreamByteBuffer(TEST_NAME, frequency, TEST_SWEEP,
+ TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ TEST_MODE, TEST_WRITE_MODE,
+ false /* useChannelIndex */, useDirect != 0);
- // create audio track and confirm settings
- AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR,
- TEST_CONF, TEST_FORMAT, minBufferSize, TEST_MODE);
- assertEquals(TEST_NAME + ": state",
- AudioTrack.STATE_INITIALIZED, track.getState());
- assertEquals(TEST_NAME + ": sample rate",
- TEST_SR, track.getSampleRate());
- assertEquals(TEST_NAME + ": channel mask",
- TEST_CONF, track.getChannelConfiguration());
- assertEquals(TEST_NAME + ": encoding",
- TEST_FORMAT, track.getAudioFormat());
-
- ByteBuffer bb = (useDirect == 1)
- ? ByteBuffer.allocateDirect(bufferSize)
- : ByteBuffer.allocate(bufferSize);
- bb.order(java.nio.ByteOrder.nativeOrder());
-
- // -------- test --------------
- switch (TEST_FORMAT) {
- case AudioFormat.ENCODING_PCM_8BIT: {
- byte data[] = AudioHelper.createSoundDataInByteArray(
- bufferSamples, TEST_SR,
- frequency, TEST_SWEEP);
- bb.put(data);
- bb.flip();
- } break;
- case AudioFormat.ENCODING_PCM_16BIT: {
- short data[] = AudioHelper.createSoundDataInShortArray(
- bufferSamples, TEST_SR,
- frequency, TEST_SWEEP);
- ShortBuffer sb = bb.asShortBuffer();
- sb.put(data);
- bb.limit(sb.limit() * 2);
- } break;
- case AudioFormat.ENCODING_PCM_FLOAT: {
- float data[] = AudioHelper.createSoundDataInFloatArray(
- bufferSamples, TEST_SR,
- frequency, TEST_SWEEP);
- FloatBuffer fb = bb.asFloatBuffer();
- fb.put(data);
- bb.limit(fb.limit() * 4);
- } break;
- }
-
- boolean hasPlayed = false;
- int written = 0;
- while (written < bufferSize) {
- int ret = track.write(bb,
- Math.min(bufferSize - written, minBufferSize),
- TEST_WRITE_MODE);
- assertTrue(TEST_NAME, ret >= 0);
- written += ret;
- if (!hasPlayed) {
- track.play();
- hasPlayed = true;
- }
- }
-
- track.stop();
- Thread.sleep(WAIT_MSEC);
- // -------- tear down --------------
- track.release();
- frequency += 200; // increment test tone frequency
+ // add a gap to make tones distinct
+ Thread.sleep(100 /* millis */);
+ frequency += 30; // increment test tone frequency
}
}
}
@@ -1991,7 +2041,9 @@
AudioTrack.WRITE_BLOCKING,
AudioTrack.WRITE_NON_BLOCKING,
};
- final float TEST_SWEEP = 0;
+ final double TEST_SWEEP = 0;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
for (int TEST_FORMAT : TEST_FORMAT_ARRAY) {
for (int TEST_CONF : TEST_CONF_ARRAY) {
@@ -1999,93 +2051,14 @@
for (int TEST_SR : TEST_SR_ARRAY) {
for (int TEST_WRITE_MODE : TEST_WRITE_MODE_ARRAY) {
for (int useDirect = 0; useDirect < 2; ++useDirect) {
- AudioFormat format = new AudioFormat.Builder()
- .setEncoding(TEST_FORMAT)
- .setSampleRate(TEST_SR)
- .setChannelIndexMask(TEST_CONF)
- .build();
- AudioTrack track = new AudioTrack.Builder()
- .setAudioFormat(format)
- .build();
- assertEquals(TEST_NAME,
- AudioTrack.STATE_INITIALIZED, track.getState());
+ playOnceStreamByteBuffer(TEST_NAME, frequency, TEST_SWEEP,
+ TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ TEST_MODE, TEST_WRITE_MODE,
+ true /* useChannelIndex */, useDirect != 0);
- // create the byte buffer and fill with test data
- final int frameSize = AudioHelper.frameSizeFromFormat(format);
- final int frameCount =
- AudioHelper.frameCountFromMsec(300 /* ms */, format);
- final int bufferSize = frameCount * frameSize;
- final int bufferSamples = frameCount * format.getChannelCount();
- ByteBuffer bb = (useDirect == 1)
- ? ByteBuffer.allocateDirect(bufferSize)
- : ByteBuffer.allocate(bufferSize);
- bb.order(java.nio.ByteOrder.nativeOrder());
-
- switch (TEST_FORMAT) {
- case AudioFormat.ENCODING_PCM_8BIT: {
- byte data[] = AudioHelper.createSoundDataInByteArray(
- bufferSamples, TEST_SR,
- frequency, TEST_SWEEP);
- bb.put(data);
- bb.flip();
- } break;
- case AudioFormat.ENCODING_PCM_16BIT: {
- short data[] = AudioHelper.createSoundDataInShortArray(
- bufferSamples, TEST_SR,
- frequency, TEST_SWEEP);
- ShortBuffer sb = bb.asShortBuffer();
- sb.put(data);
- bb.limit(sb.limit() * 2);
- } break;
- case AudioFormat.ENCODING_PCM_FLOAT: {
- float data[] = AudioHelper.createSoundDataInFloatArray(
- bufferSamples, TEST_SR,
- frequency, TEST_SWEEP);
- FloatBuffer fb = bb.asFloatBuffer();
- fb.put(data);
- bb.limit(fb.limit() * 4);
- } break;
- }
-
- // start the AudioTrack
- // This can be done before or after the first write.
- // Current behavior for streaming tracks is that
- // actual playback does not begin before the internal
- // data buffer is completely full.
- track.play();
-
- // write data
- final long startTime = System.currentTimeMillis();
- final long maxDuration = frameCount * 1000 / TEST_SR + 1000;
- for (int written = 0; written < bufferSize; ) {
- // ret may return a short count if write
- // is non blocking or even if write is blocking
- // when a stop/pause/flush is issued from another thread.
- final int kBatchFrames = 1000;
- int ret = track.write(bb,
- Math.min(bufferSize - written, frameSize * kBatchFrames),
- TEST_WRITE_MODE);
- // for non-blocking mode, this loop may spin quickly
- assertTrue(TEST_NAME + ": write error " + ret, ret >= 0);
- assertTrue(TEST_NAME + ": write timeout",
- (System.currentTimeMillis() - startTime) <= maxDuration);
- written += ret;
- }
-
- // for streaming tracks, stop will allow the rest of the data to
- // drain out, but we don't know how long to wait unless
- // we check the position before stop. if we check position
- // after we stop, we read 0.
- final int position = track.getPlaybackHeadPosition();
- final int remainingTimeMs = (int)((double)(frameCount - position)
- * 1000 / TEST_SR);
- track.stop();
- Thread.sleep(remainingTimeMs);
- // tear down
- track.release();
// add a gap to make tones distinct
Thread.sleep(100 /* millis */);
- frequency += 200; // increment test tone frequency
+ frequency += 30; // increment test tone frequency
}
}
}
@@ -2911,6 +2884,334 @@
audioTrack.getAudioDescriptionMixLeveldB(), 0.f /*delta*/);
}
+ /*
+ * The following helpers and tests are used to test setting
+ * and getting the start threshold in frames.
+ *
+ * See Android CDD 5.6 [C-1-2] Cold output latency
+ */
+ private static final int START_THRESHOLD_SLEEP_MILLIS = 500;
+
+ /**
+ * Helper test that validates setting the start threshold.
+ *
+ * @param track
+ * @param startThresholdInFrames
+ * @throws Exception
+ */
+ private static void validateSetStartThresholdInFrames(
+ AudioTrack track, int startThresholdInFrames) throws Exception {
+ assertEquals(startThresholdInFrames,
+ track.setStartThresholdInFrames(startThresholdInFrames));
+ assertEquals(startThresholdInFrames,
+ track.getStartThresholdInFrames());
+ }
+
+ /**
+ * Helper that tests that the head position eventually equals expectedFrames.
+ *
+ * Exponential backoff to ~ 2 x START_THRESHOLD_SLEEP_MILLIS
+ *
+ * @param track
+ * @param expectedFrames
+ * @param message
+ * @throws Exception
+ */
+ private static void validatePlaybackHeadPosition(
+ AudioTrack track, int expectedFrames, String message) throws Exception {
+ int cumulativeMillis = 0;
+ int playbackHeadPosition = 0;
+ for (double testMillis = START_THRESHOLD_SLEEP_MILLIS * 0.125;
+ testMillis <= START_THRESHOLD_SLEEP_MILLIS; // this is exact for IEEE binary double
+ testMillis *= 2.) {
+ Thread.sleep((int)testMillis);
+ playbackHeadPosition = track.getPlaybackHeadPosition();
+ if (playbackHeadPosition == expectedFrames) return;
+ cumulativeMillis += (int)testMillis;
+ }
+ fail(message + ": expected track playbackHeadPosition: " + expectedFrames
+ + " actual playbackHeadPosition: " + playbackHeadPosition
+ + " wait time: " + cumulativeMillis + "ms");
+ }
+
+ /**
+ * Helper test that sets the start threshold to frames, and validates
+ * writing exactly frames amount of data is needed to start the
+ * track streaming.
+ *
+ * @param track
+ * @param frames
+ * @throws Exception
+ */
+ private static void validateWriteStartsStream(
+ AudioTrack track, int frames) throws Exception {
+ assertEquals(1, track.getChannelCount()); // must be MONO
+ final short[] data = new short[frames];
+
+ // The track must be idle/underrun or the test will fail.
+ int expectedFrames = track.getPlaybackHeadPosition();
+
+ // Set our threshold to frames.
+ validateSetStartThresholdInFrames(track, frames);
+
+ Thread.sleep(START_THRESHOLD_SLEEP_MILLIS);
+ assertEquals("Changing start threshold doesn't start if it is larger than buffer data",
+ expectedFrames, track.getPlaybackHeadPosition());
+
+ // Write a small amount of data, this isn't enough to start the track.
+ final int PARTIAL_WRITE_IN_FRAMES = frames - 1;
+ track.write(data, 0 /* offsetInShorts */, PARTIAL_WRITE_IN_FRAMES);
+
+ // Ensure the track hasn't started.
+ Thread.sleep(START_THRESHOLD_SLEEP_MILLIS);
+ assertEquals("Track needs enough frames to start",
+ expectedFrames, track.getPlaybackHeadPosition());
+
+ // Write exactly threshold frames out, this should kick the playback off.
+ track.write(data, 0 /* offsetInShorts */, data.length - PARTIAL_WRITE_IN_FRAMES);
+
+ // Verify that we have processed the data now.
+ expectedFrames += frames;
+ Thread.sleep(frames * 1000L / track.getSampleRate()); // accommodate for #frames.
+ validatePlaybackHeadPosition(track, expectedFrames,
+ "Writing buffer data to start threshold should start streaming");
+ }
+
+ /**
+ * Helper that tests reducing the start threshold to frames will start track
+ * streaming when frames of data are written to it. (Presumes the
+ * previous start threshold was greater than frames).
+ *
+ * @param track
+ * @param frames
+ * @throws Exception
+ */
+ private static void validateSetStartThresholdStartsStream(
+ AudioTrack track, int frames) throws Exception {
+ assertTrue(track.getStartThresholdInFrames() > frames);
+ assertEquals(1, track.getChannelCount()); // must be MONO
+ final short[] data = new short[frames];
+
+ // The track must be idle/underrun or the test will fail.
+ int expectedFrames = track.getPlaybackHeadPosition();
+
+ // This write is too small for now.
+ track.write(data, 0 /* offsetInShorts */, data.length);
+
+ Thread.sleep(START_THRESHOLD_SLEEP_MILLIS);
+ assertEquals("Track needs enough frames to start",
+ expectedFrames, track.getPlaybackHeadPosition());
+
+ // Reduce our start threshold. This should start streaming.
+ validateSetStartThresholdInFrames(track, frames);
+
+ // Verify that we have processed the data now.
+ expectedFrames += frames;
+ Thread.sleep(frames * 1000L / track.getSampleRate()); // accommodate for #frames.
+ validatePlaybackHeadPosition(track, expectedFrames,
+ "Changing start threshold to buffer data level should start streaming");
+ }
+
+ // Start threshold levels that we check.
+ private enum ThresholdLevel { LOW, MEDIUM, HIGH };
+ @Test
+ public void testStartThresholdInFrames() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+
+ for (ThresholdLevel level : new ThresholdLevel[] {
+ ThresholdLevel.LOW, ThresholdLevel.MEDIUM, ThresholdLevel.HIGH}) {
+ AudioTrack audioTrack = null;
+ try {
+ // Build our audiotrack
+ audioTrack = new AudioTrack.Builder()
+ .setAudioFormat(new AudioFormat.Builder()
+ .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
+ .setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
+ .build())
+ .build();
+
+ // Initially the start threshold must be the same as the buffer size in frames.
+ final int bufferSizeInFrames = audioTrack.getBufferSizeInFrames();
+ assertEquals("At start, getBufferSizeInFrames should equal getStartThresholdInFrames",
+ bufferSizeInFrames,
+ audioTrack.getStartThresholdInFrames());
+
+ final int TARGET_THRESHOLD_IN_FRAMES; // threshold level to verify
+ switch (level) {
+ default:
+ case LOW:
+ TARGET_THRESHOLD_IN_FRAMES = 2;
+ break;
+ case MEDIUM:
+ TARGET_THRESHOLD_IN_FRAMES = bufferSizeInFrames / 2;
+ break;
+ case HIGH:
+ TARGET_THRESHOLD_IN_FRAMES = bufferSizeInFrames - 1;
+ break;
+ }
+
+ // Skip extreme cases that don't need testing.
+ if (TARGET_THRESHOLD_IN_FRAMES < 2
+ || TARGET_THRESHOLD_IN_FRAMES >= bufferSizeInFrames) continue;
+
+ // Start the AudioTrack. Now the track is waiting for data.
+ audioTrack.play();
+
+ validateWriteStartsStream(audioTrack, TARGET_THRESHOLD_IN_FRAMES);
+
+ // Try a condition that requires buffers to be filled again.
+ if (false) {
+ // Only a deep underrun when the track becomes inactive requires a refill.
+ // Disabled as this is dependent on underlying MixerThread timeouts.
+ Thread.sleep(5000 /* millis */);
+ } else {
+ // Flushing will require a refill (this does not require timing).
+ audioTrack.pause();
+ audioTrack.flush();
+ audioTrack.play();
+ }
+
+ // Check that reducing to a smaller threshold will start the track streaming.
+ validateSetStartThresholdStartsStream(audioTrack, TARGET_THRESHOLD_IN_FRAMES - 1);
+ } finally {
+ if (audioTrack != null) {
+ audioTrack.release();
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testStartThresholdInFramesExceptions() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+ AudioTrack audioTrack = null;
+ try {
+ // Build our audiotrack
+ audioTrack = new AudioTrack.Builder()
+ .setAudioFormat(new AudioFormat.Builder()
+ .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
+ .setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
+ .build())
+ .build();
+
+ // Test setting invalid start threshold.
+ final AudioTrack track = audioTrack; // make final for lambda
+ assertThrows(IllegalArgumentException.class, () -> {
+ track.setStartThresholdInFrames(-1 /* startThresholdInFrames */);
+ });
+ } finally {
+ if (audioTrack != null) {
+ audioTrack.release();
+ }
+ }
+ // If we're here audioTrack should be non-null but released,
+ // so calls should return an IllegalStateException.
+ final AudioTrack track = audioTrack; // make final for lambda
+ assertThrows(IllegalStateException.class, () -> {
+ track.getStartThresholdInFrames();
+ });
+ assertThrows(IllegalStateException.class, () -> {
+ track.setStartThresholdInFrames(1 /* setStartThresholdInFrames */);
+ });
+ }
+
+ /**
+ * Tests height channel masks and higher channel counts
+ * used in immersive AudioTrack streaming.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testImmersiveStreaming() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+
+ final String TEST_NAME = "testImmersiveStreaming";
+ final int TEST_FORMAT_ARRAY[] = {
+ AudioFormat.ENCODING_PCM_16BIT,
+ AudioFormat.ENCODING_PCM_FLOAT,
+ };
+ final int TEST_SR_ARRAY[] = {
+ 48000, // do not set too high - costly in memory.
+ };
+ final int TEST_CONF_ARRAY[] = {
+ AudioFormat.CHANNEL_OUT_5POINT1POINT2, // 8 ch (includes height channels vs 7.1).
+ AudioFormat.CHANNEL_OUT_7POINT1POINT4, // 12 ch
+ AudioFormat.CHANNEL_OUT_22POINT2, // 24 ch
+ };
+
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+ final float TEST_SWEEP = 0; // sine wave only
+ final boolean TEST_IS_LOW_RAM_DEVICE = false;
+ for (int TEST_FORMAT : TEST_FORMAT_ARRAY) {
+ double frequency = 400; // Note: frequency changes for each test
+ for (int TEST_SR : TEST_SR_ARRAY) {
+ for (int TEST_CONF : TEST_CONF_ARRAY) {
+ if (AudioFormat.channelCountFromOutChannelMask(TEST_CONF)
+ > AudioSystem.OUT_CHANNEL_COUNT_MAX) {
+ continue; // Skip if the channel count exceeds framework capabilities.
+ }
+ playOnceStreamData(TEST_NAME, TEST_MODE, TEST_STREAM_TYPE, TEST_SWEEP,
+ TEST_IS_LOW_RAM_DEVICE, TEST_FORMAT, frequency, TEST_SR, TEST_CONF,
+ WAIT_MSEC);
+ frequency += 50; // increment test tone frequency
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testImmersiveChannelIndex() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+
+ final String TEST_NAME = "testImmersiveChannelIndex";
+ final int TEST_FORMAT_ARRAY[] = {
+ AudioFormat.ENCODING_PCM_FLOAT,
+ };
+ final int TEST_SR_ARRAY[] = {
+ 48000, // do not set too high - costly in memory.
+ };
+ final int MAX_CHANNEL_BIT = 1 << (AudioSystem.FCC_24 - 1); // highest allowed channel.
+ final int TEST_CONF_ARRAY[] = {
+ (1 << AudioSystem.OUT_CHANNEL_COUNT_MAX) - 1,
+ MAX_CHANNEL_BIT, // likely silent - no physical device on top channel.
+ MAX_CHANNEL_BIT | 1, // first channel will likely have physical device.
+ };
+ final int TEST_WRITE_MODE_ARRAY[] = {
+ AudioTrack.WRITE_BLOCKING,
+ AudioTrack.WRITE_NON_BLOCKING,
+ };
+ final double TEST_SWEEP = 0;
+ final int TEST_TRANSFER_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ double frequency = 200; // frequency changes for each test
+ for (int TEST_FORMAT : TEST_FORMAT_ARRAY) {
+ for (int TEST_CONF : TEST_CONF_ARRAY) {
+ for (int TEST_SR : TEST_SR_ARRAY) {
+ for (int TEST_WRITE_MODE : TEST_WRITE_MODE_ARRAY) {
+ for (int useDirect = 0; useDirect < 2; ++useDirect) {
+ playOnceStreamByteBuffer(
+ TEST_NAME, frequency, TEST_SWEEP,
+ TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ TEST_TRANSFER_MODE, TEST_WRITE_MODE,
+ true /* useChannelIndex */, useDirect != 0);
+ frequency += 30; // increment test tone frequency
+ }
+ }
+ }
+ }
+ }
+ }
+
/* Do not run in JB-MR1. will be re-opened in the next platform release.
public void testResourceLeakage() throws Exception {
final int BUFFER_SIZE = 600 * 1024;
diff --git a/tests/tests/media/src/android/media/cts/DecodeEditEncodeTest.java b/tests/tests/media/src/android/media/cts/DecodeEditEncodeTest.java
index 0803da3..4bada72 100644
--- a/tests/tests/media/src/android/media/cts/DecodeEditEncodeTest.java
+++ b/tests/tests/media/src/android/media/cts/DecodeEditEncodeTest.java
@@ -60,7 +60,19 @@
private static final String KEY_ALLOW_FRAME_DROP = "allow-frame-drop";
// movie length, in frames
- private static final int NUM_FRAMES = 30; // two seconds of video
+ private static final int NUM_FRAMES = FRAME_RATE * 3; // three seconds of video
+
+ // since encoders are lossy, we treat the first N frames differently, with a different
+ // tolerance, than the remainder of the clip. The # of such frames is
+ // INITIAL_TOLERANCE_FRAME_LIMIT, the tolerance within that window is defined by
+ // INITIAL_TOLERANCE and the tolerance afterwards is defined by TOLERANCE
+ private final int INITIAL_TOLERANCE_FRAME_LIMIT = FRAME_RATE * 2;
+
+ // allowed error between input and output
+ private static final int TOLERANCE = 8;
+
+ // allowed error between input and output for initial INITIAL_TOLERANCE_FRAME_LIMIT frames
+ private static final int INITIAL_TOLERANCE = 10;
private static final int TEST_R0 = 0; // dull green background
private static final int TEST_G0 = 136;
@@ -733,9 +745,10 @@
info.presentationTimeUs);
surface.awaitNewImage();
surface.drawImage();
- if (!checkSurfaceFrame(checkIndex++)) {
+ if (!checkSurfaceFrame(checkIndex)) {
badFrames++;
}
+ checkIndex++;
}
}
}
@@ -752,7 +765,8 @@
private boolean checkSurfaceFrame(int frameIndex) {
ByteBuffer pixelBuf = ByteBuffer.allocateDirect(4); // TODO - reuse this
boolean frameFailed = false;
-
+ // Choose the appropriate initial/regular tolerance
+ int maxDelta = frameIndex < INITIAL_TOLERANCE_FRAME_LIMIT ? INITIAL_TOLERANCE : TOLERANCE;
for (int i = 0; i < 8; i++) {
// Note the coordinates are inverted on the Y-axis in GL.
int x, y;
@@ -782,12 +796,12 @@
expG = TEST_B0;
expB = TEST_G0;
}
- if (!isColorClose(r, expR) ||
- !isColorClose(g, expG) ||
- !isColorClose(b, expB)) {
+ if (!isColorClose(r, expR, maxDelta) ||
+ !isColorClose(g, expG, maxDelta) ||
+ !isColorClose(b, expB, maxDelta)) {
Log.w(TAG, "Bad frame " + frameIndex + " (rect=" + i + ": rgb=" + r +
"," + g + "," + b + " vs. expected " + expR + "," + expG +
- "," + expB + ")");
+ "," + expB + ") for allowed error of " + maxDelta);
frameFailed = true;
}
}
@@ -799,13 +813,12 @@
* Returns true if the actual color value is close to the expected color value. Updates
* mLargestColorDelta.
*/
- boolean isColorClose(int actual, int expected) {
- final int MAX_DELTA = 8;
+ boolean isColorClose(int actual, int expected, int maxDelta) {
int delta = Math.abs(actual - expected);
if (delta > mLargestColorDelta) {
mLargestColorDelta = delta;
}
- return (delta <= MAX_DELTA);
+ return (delta <= maxDelta);
}
/**
diff --git a/tests/tests/media/src/android/media/cts/DecoderConformanceTest.java b/tests/tests/media/src/android/media/cts/DecoderConformanceTest.java
index 258fd7a..7a5acbe 100644
--- a/tests/tests/media/src/android/media/cts/DecoderConformanceTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderConformanceTest.java
@@ -189,6 +189,7 @@
if (stat == Status.PASS) {
pass = true;
} else if (stat == Status.SKIP) {
+ release();
continue;
}
} catch (Exception e) {
diff --git a/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java b/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
index 5009f58..b82019a 100755
--- a/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
+++ b/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
@@ -28,6 +28,7 @@
import android.test.AndroidTestCase;
import android.util.Log;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.compatibility.common.util.MediaUtils;
@@ -54,6 +55,8 @@
@Presubmit
@SmallTest
@RequiresDevice
+// TODO: b/186001256
+@FlakyTest
public class EncodeDecodeTest extends AndroidTestCase {
private static final String TAG = "EncodeDecodeTest";
private static final boolean VERBOSE = false; // lots of logging
diff --git a/tests/tests/media/src/android/media/cts/HeifWriterTest.java b/tests/tests/media/src/android/media/cts/HeifWriterTest.java
index 7f1c0d6..40d6128 100644
--- a/tests/tests/media/src/android/media/cts/HeifWriterTest.java
+++ b/tests/tests/media/src/android/media/cts/HeifWriterTest.java
@@ -52,6 +52,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.heifwriter.HeifWriter;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.compatibility.common.util.ApiLevelUtil;
@@ -171,21 +172,26 @@
doTestForVariousNumberImages(builder);
}
+ // TODO: b/186001256
+ @FlakyTest
public void testInputSurface_NoGrid_NoHandler() throws Throwable {
TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_SURFACE, false, false);
doTestForVariousNumberImages(builder);
}
+ @FlakyTest
public void testInputSurface_Grid_NoHandler() throws Throwable {
TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_SURFACE, true, false);
doTestForVariousNumberImages(builder);
}
+ @FlakyTest
public void testInputSurface_NoGrid_Handler() throws Throwable {
TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_SURFACE, false, true);
doTestForVariousNumberImages(builder);
}
+ @FlakyTest
public void testInputSurface_Grid_Handler() throws Throwable {
TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_SURFACE, true, true);
doTestForVariousNumberImages(builder);
diff --git a/tests/tests/media/src/android/media/cts/ImageReaderDecoderTest.java b/tests/tests/media/src/android/media/cts/ImageReaderDecoderTest.java
index ff61af0..dcd592c 100644
--- a/tests/tests/media/src/android/media/cts/ImageReaderDecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/ImageReaderDecoderTest.java
@@ -44,6 +44,7 @@
import android.util.Log;
import android.view.Surface;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.compatibility.common.util.MediaUtils;
@@ -393,11 +394,16 @@
public void testGoogVP8ImageReader() { swirlTest(googVP8(), MODE_IMAGEREADER); }
public void testGoogVP9ImageReader() { swirlTest(googVP9(), MODE_IMAGEREADER); }
+ // TODO: b/186001256
+ @FlakyTest
public void testOtherH265ImageReader() { swirlTest(otherH265(), MODE_IMAGEREADER); }
+ @FlakyTest
public void testOtherH264ImageReader() { swirlTest(otherH264(), MODE_IMAGEREADER); }
public void testOtherH263ImageReader() { swirlTest(otherH263(), MODE_IMAGEREADER); }
public void testOtherMpeg4ImageReader() { swirlTest(otherMpeg4(), MODE_IMAGEREADER); }
+ @FlakyTest
public void testOtherVP8ImageReader() { swirlTest(otherVP8(), MODE_IMAGEREADER); }
+ @FlakyTest
public void testOtherVP9ImageReader() { swirlTest(otherVP9(), MODE_IMAGEREADER); }
/**
diff --git a/tests/tests/media/src/android/media/cts/MediaCasTest.java b/tests/tests/media/src/android/media/cts/MediaCasTest.java
index a3b9176..268c34d 100644
--- a/tests/tests/media/src/android/media/cts/MediaCasTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCasTest.java
@@ -28,6 +28,7 @@
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
+import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresDevice;
import android.test.AndroidTestCase;
@@ -51,6 +52,7 @@
@Presubmit
@SmallTest
@RequiresDevice
+@AppModeFull(reason = "TODO: evaluate and port to instant")
public class MediaCasTest extends AndroidTestCase {
private static final String TAG = "MediaCasTest";
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecTest.java b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
index 1176dd8..e764ac5 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
@@ -125,6 +125,8 @@
private static final int DECODING_TIMEOUT_MS = 10000;
private static boolean mIsAtLeastR = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R);
+ private static boolean mIsAtLeastS = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S);
+
/**
* Tests:
* <br> Exceptions for MediaCodec factory methods
@@ -382,6 +384,38 @@
fail("stop should not return MediaCodec.CodecException on wrong state");
} catch (IllegalStateException e) { // expected
}
+ try {
+ codec.getSupportedVendorParameters();
+ fail("getSupportedVendorParameters should throw IllegalStateException" +
+ " when in Uninitialized state");
+ } catch (IllegalStateException e) { // expected
+ } catch (Exception e) {
+ fail("unexpected exception: " + e.toString());
+ }
+ try {
+ codec.getParameterDescriptor("");
+ fail("getParameterDescriptor should throw IllegalStateException" +
+ " when in Uninitialized state");
+ } catch (IllegalStateException e) { // expected
+ } catch (Exception e) {
+ fail("unexpected exception: " + e.toString());
+ }
+ try {
+ codec.subscribeToVendorParameters(List.of(""));
+ fail("subscribeToVendorParameters should throw IllegalStateException" +
+ " when in Uninitialized state");
+ } catch (IllegalStateException e) { // expected
+ } catch (Exception e) {
+ fail("unexpected exception: " + e.toString());
+ }
+ try {
+ codec.unsubscribeFromVendorParameters(List.of(""));
+ fail("unsubscribeFromVendorParameters should throw IllegalStateException" +
+ " when in Uninitialized state");
+ } catch (IllegalStateException e) { // expected
+ } catch (Exception e) {
+ fail("unexpected exception: " + e.toString());
+ }
if (mIsAtLeastR) {
// recreate
@@ -2781,4 +2815,82 @@
}
}
}
+
+ public void testVendorParameters() {
+ if (!MediaUtils.check(mIsAtLeastS, "test needs Android 12")) {
+ return;
+ }
+ MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ for (MediaCodecInfo info : mcl.getCodecInfos()) {
+ if (info.isAlias()) {
+ continue;
+ }
+ MediaCodec codec = null;
+ try {
+ codec = MediaCodec.createByCodecName(info.getName());
+ List<String> vendorParams = codec.getSupportedVendorParameters();
+ if (VERBOSE) {
+ Log.d(TAG, "vendor params supported by " + info.getName() + ": " +
+ vendorParams.toString());
+ }
+ for (String name : vendorParams) {
+ MediaCodec.ParameterDescriptor desc = codec.getParameterDescriptor(name);
+ assertNotNull(name + " is in the list of supported parameters, so the codec" +
+ " should be able to describe it.", desc);
+ assertEquals("name differs from the name in the descriptor",
+ name, desc.getName());
+ assertTrue("type in the descriptor cannot be TYPE_NULL",
+ MediaFormat.TYPE_NULL != desc.getType());
+ if (VERBOSE) {
+ Log.d(TAG, name + " is of type " + desc.getType());
+ }
+ }
+ codec.subscribeToVendorParameters(vendorParams);
+
+ // Build a MediaFormat that makes sense to the codec.
+ String type = info.getSupportedTypes()[0];
+ MediaFormat format = null;
+ CodecCapabilities caps = info.getCapabilitiesForType(type);
+ AudioCapabilities audioCaps = caps.getAudioCapabilities();
+ VideoCapabilities videoCaps = caps.getVideoCapabilities();
+ if (audioCaps != null) {
+ format = MediaFormat.createAudioFormat(
+ type,
+ audioCaps.getMaxInputChannelCount(),
+ audioCaps.getSupportedSampleRateRanges()[0].getLower());
+ if (info.isEncoder()) {
+ format.setInteger(MediaFormat.KEY_BIT_RATE, AUDIO_BIT_RATE);
+ }
+ } else if (videoCaps != null) {
+ int width = videoCaps.getSupportedWidths().getLower();
+ int height = videoCaps.getSupportedHeightsFor(width).getLower();
+ format = MediaFormat.createVideoFormat(type, width, height);
+ if (info.isEncoder()) {
+ format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
+ format.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
+ format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
+ format.setInteger(
+ MediaFormat.KEY_COLOR_FORMAT,
+ CodecCapabilities.COLOR_FormatYUV420Flexible);
+ }
+ } else {
+ Log.i(TAG, info.getName() + " is in neither audio nor video domain; skipped");
+ codec.release();
+ continue;
+ }
+ codec.configure(
+ format, null, null,
+ info.isEncoder() ? MediaCodec.CONFIGURE_FLAG_ENCODE : 0);
+ codec.start();
+ codec.unsubscribeFromVendorParameters(vendorParams);
+ codec.stop();
+ } catch (Exception e) {
+ throw new RuntimeException("codec name: " + info.getName(), e);
+ } finally {
+ if (codec != null) {
+ codec.release();
+ }
+ }
+ }
+ }
}
diff --git a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
index 48e9810..fe9c30d 100644
--- a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
@@ -73,6 +73,7 @@
private static final UUID UUID_WIDEVINE = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL);
private static final UUID UUID_PLAYREADY = new UUID(0x9A04F07998404286L, 0xAB92E65BE0885F95L);
private static boolean mIsAtLeastR = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R);
+ private static final boolean IS_AT_LEAST_S = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S);
static final String mInpPrefix = WorkDir.getMediaDirString();
protected MediaExtractor mExtractor;
@@ -429,6 +430,53 @@
assertEquals("video/av01", mimeType);
}
+ //MPEG-H 3D Audio single stream (mha1)
+ public void testMpegh3dAudioMediaExtractorMha1() throws Exception {
+ // TODO(b/186267251) move file to cloud storage.
+ AssetFileDescriptor afd = getContext().getResources()
+ .openRawResourceFd(R.raw.sample_mpegh_mha1);
+ mExtractor.setDataSource(afd);
+ assertEquals(1, mExtractor.getTrackCount());
+
+ // The following values below require API Build.VERSION_CODES.S
+ if (!MediaUtils.check(IS_AT_LEAST_S, "test needs Android 12")) return;
+
+ MediaFormat trackFormat = mExtractor.getTrackFormat(0);
+ final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+ assertEquals(MediaFormat.MIMETYPE_AUDIO_MPEGH_MHA1, mimeType);
+
+ final int hpli = trackFormat.getInteger(MediaFormat.KEY_MPEGH_PROFILE_LEVEL_INDICATION);
+ assertEquals(0x0D, hpli);
+
+ final int hrcl = trackFormat.getInteger(MediaFormat.KEY_MPEGH_REFERENCE_CHANNEL_LAYOUT);
+ assertEquals(0x13, hrcl);
+ }
+
+ //MPEG-H 3D Audio single stream encapsulated in MHAS (mhm1)
+ public void testMpegh3dAudioMediaExtractorMhm1() throws Exception {
+ // TODO(b/186267251) move file to cloud storage.
+ AssetFileDescriptor afd = getContext().getResources()
+ .openRawResourceFd(R.raw.sample_mpegh_mhm1);
+ mExtractor.setDataSource(afd);
+ assertEquals(1, mExtractor.getTrackCount());
+
+ // The following values below require API Build.VERSION_CODES.S
+ if (!MediaUtils.check(IS_AT_LEAST_S, "test needs Android 12")) return;
+
+ MediaFormat trackFormat = mExtractor.getTrackFormat(0);
+ final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+ assertEquals(MediaFormat.MIMETYPE_AUDIO_MPEGH_MHM1, mimeType);
+
+ final int hpli = trackFormat.getInteger(MediaFormat.KEY_MPEGH_PROFILE_LEVEL_INDICATION);
+ assertEquals(0x0D, hpli);
+
+ final int hrcl = trackFormat.getInteger(MediaFormat.KEY_MPEGH_REFERENCE_CHANNEL_LAYOUT);
+ assertEquals(0x13, hrcl);
+
+ final ByteBuffer hcos = trackFormat.getByteBuffer(MediaFormat.KEY_MPEGH_COMPATIBLE_SETS);
+ assertEquals(0x12, hcos.get());
+ }
+
public void testGetDrmInitData() throws Exception {
if (!MediaUtils.check(mIsAtLeastR, "test needs Android 11")) return;
setDataSource("psshtest.mp4");
diff --git a/tests/tests/media/src/android/media/cts/MediaFormatTest.java b/tests/tests/media/src/android/media/cts/MediaFormatTest.java
index 2beae2b..18a7add 100644
--- a/tests/tests/media/src/android/media/cts/MediaFormatTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaFormatTest.java
@@ -16,16 +16,30 @@
package android.media.cts;
+import android.annotation.NonNull;
import android.media.MediaFormat;
import android.test.AndroidTestCase;
+import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+
+import java.lang.reflect.Field;
import java.nio.ByteBuffer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
public class MediaFormatTest extends AndroidTestCase {
+ private static final String TAG = "MediaFormatTest";
private static ByteBuffer defaultByteBuffer = ByteBuffer.allocateDirect(16);
private void assertGetByteBuffersThrowClassCastException(
@@ -635,4 +649,183 @@
assertEquals(1, other.getFeatures().size());
}
}
+
+ /**
+ * Check MediaFormat key name and string value consistency.
+ *
+ * The canonical key reads something like this:
+ * KEY_SOMETHING_HERE = "something-here";
+ *
+ * An exclusion list allows arbitrary keys as needed.
+ *
+ * This test uses introspection to find the key fields.
+ *
+ * @throws Exception
+ */
+ public void testKeyConsistency() throws Exception {
+ // Legacy MediaFormat keys inconsistent with the canonical format.
+ final Set<String> exclusions = Stream.of(
+ // <aac-drc-[cut-level]>
+ "KEY_AAC_DRC_ATTENUATION_FACTOR",
+ // <aac-drc-boost-[level]>
+ "KEY_AAC_DRC_BOOST_FACTOR",
+ // <aac-[target-ref]-level>
+ "KEY_AAC_DRC_TARGET_REFERENCE_LEVEL",
+ // <...c-max-output-channel[_]count>
+ "KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT",
+ // <bit[]rate>
+ "KEY_BIT_RATE",
+ // <create-input-[buffers]-suspended>
+ "KEY_CREATE_INPUT_SURFACE_SUSPENDED",
+ // <duration[u]s>
+ "KEY_DURATION",
+ // <grid-col[]s>
+ "KEY_GRID_COLUMNS",
+ // <h[w]-av-sync-id>
+ "KEY_HARDWARE_AV_SYNC_ID",
+ // <max-bit[]rate>
+ "KEY_MAX_BIT_RATE",
+ // <max-b[]frames>
+ "KEY_MAX_B_FRAMES",
+ // <[sar]-height>
+ "KEY_PIXEL_ASPECT_RATIO_HEIGHT",
+ // <[sar]-width>
+ "KEY_PIXEL_ASPECT_RATIO_WIDTH",
+ // <prepend-[sps-pps-to-idr]-frames>
+ "KEY_PREPEND_HEADER_TO_SYNC_FRAMES",
+ // <...h-blank-buffers-on-s[hutdown]>
+ "KEY_PUSH_BLANK_BUFFERS_ON_STOP",
+ // <rotation[-degrees]>
+ "KEY_ROTATION",
+ // <t[s-schema]>
+ "KEY_TEMPORAL_LAYERING"
+ ).collect(Collectors.toCollection(HashSet::new));
+
+ ArrayList<String> failures = new ArrayList<>();
+ final Field[] fields = MediaFormat.class.getFields();
+ for (Field field : fields) {
+ final String key = field.getName();
+ if (!key.startsWith("KEY_")) continue;
+ if (exclusions.contains(key)) continue;
+
+ if (!key.equals(key.toUpperCase())) {
+ failures.add("Key field " + key + " must be upper case");
+ }
+ final String value = (String)field.get(null);
+ assertEquals("String value " + value + " must be lower case",
+ value.toLowerCase(), value);
+
+ // What do we expect the key should look like for the value?
+ final String checkKey = "KEY_" + value.toUpperCase().replace('-', '_');
+ if (!checkKey.equals(key)) {
+ failures.add("Key field " + key + " should represent value " + value
+ + " expected(" + checkKey + ")");
+ }
+ }
+ // There may be special vendor keys that are public.
+ // Log failures but don't fail test.
+ logFailures("testKeyConsistency", failures);
+ }
+
+ /**
+ * Check MediaFormat mime type field name and string value consistency.
+ *
+ * The typical mime type field reads as follows:
+ * MIMETYPE_CATEGORY_ANYCASE_HERE = "category/anYCaSE[-.+]HeRE";
+ *
+ * See here for the Internet Assigned Numbers Authority (IANA) list of media mime types:
+ * https://www.iana.org/assignments/media-types/media-types.xhtml
+ *
+ * An exclusion list allows arbitrary keys as needed.
+ *
+ * This test uses introspection to find the mime type fields.
+ *
+ * @throws Exception
+ */
+ public void testMimeTypeConsistency() throws Exception {
+ // Legacy inconsistent mime types with the exception
+ final Set<String> exclusions = Stream.of(
+ // <audio/[mp4a-latm]>
+ "MIMETYPE_AUDIO_AAC",
+ // <audio/[3gpp]>
+ "MIMETYPE_AUDIO_AMR_NB",
+ // audio/mhm1
+ "MIMETYPE_AUDIO_MPEGH_MHM1",
+ // audio/mha1
+ "MIMETYPE_AUDIO_MPEGH_MHA1",
+ // <audio/[]gsm>
+ "MIMETYPE_AUDIO_MSGSM",
+ // <image/[vnd.android.]heic>
+ "MIMETYPE_IMAGE_ANDROID_HEIC",
+ // <[application/x-]subrip>
+ "MIMETYPE_TEXT_SUBRIP",
+ // <video/av[0]1>
+ "MIMETYPE_VIDEO_AV1",
+ // <video/[3gpp]>
+ "MIMETYPE_VIDEO_H263",
+ // <video/mp[4v-es]>
+ "MIMETYPE_VIDEO_MPEG4",
+ // <video/[x-vnd.on2.]vp8>
+ "MIMETYPE_VIDEO_VP8",
+ // <video/[x-vnd.on2.]vp9>
+ "MIMETYPE_VIDEO_VP9"
+ ).collect(Collectors.toCollection(HashSet::new));
+
+ ArrayList<String> failures = new ArrayList<>();
+ final Field[] fields = MediaFormat.class.getFields();
+ for (Field field : fields) {
+ final String mimeType = field.getName();
+
+ if (!mimeType.startsWith("MIMETYPE_")) continue;
+ if (exclusions.contains(mimeType)) continue;
+
+ if (!mimeType.equals(mimeType.toUpperCase())) {
+ failures.add("mimeType field " + mimeType + " must be upper case");
+ continue;
+ }
+ final String value = (String)field.get(null);
+
+ // What do we expect the mime type field should be for the value?
+ final String checkMime = "MIMETYPE_"
+ + value.toUpperCase().replace('/', '_').replace('-', '_')
+ .replace('.', '_').replace('+', '_');
+ if (!mimeType.equals(checkMime)) {
+ failures.add("Mime type " + mimeType
+ + " should represent value " + value
+ + " expected(" + checkMime + ")");
+ }
+ }
+ // There may be special vendor keys that are public.
+ // Log failures but don't fail test.
+ logFailures("testMimeTypeConsistency", failures);
+ }
+
+ private static final String REPORT_LOG_NAME = "CtsMediaTestCases";
+ private static final int REPORT_SUMMARY_MAX_KEY_LEN = 240;
+
+ /**
+ * Log failures on atest, but don't raise an exception or fail CTS.
+ *
+ * This part is tricky:
+ * 1) We create a device report log so it is visible on the host.
+ * 2) We also write to logcat.
+ */
+ private static void logFailures(@NonNull String logName, @NonNull List<String> failures) {
+ if (failures.size() > 0) {
+ DeviceReportLog log = new DeviceReportLog(REPORT_LOG_NAME, logName);
+ StringBuilder sb = new StringBuilder("FAILED ON: ");
+ int i = 0;
+ for (String failure : failures) {
+ Log.w(TAG, failure);
+ log.addValue("failure_" + i++, failure, ResultType.NEUTRAL, ResultUnit.NONE);
+ sb.append("[" + failure + "] ");
+ }
+ if (sb.length() > REPORT_SUMMARY_MAX_KEY_LEN) {
+ sb.setLength(REPORT_SUMMARY_MAX_KEY_LEN);
+ }
+ log.setSummary(sb.toString(), failures.size(),
+ ResultType.LOWER_BETTER, ResultUnit.COUNT);
+ log.submit(InstrumentationRegistry.getInstrumentation());
+ }
+ }
}
diff --git a/tests/tests/media/src/android/media/cts/MediaStubActivity.java b/tests/tests/media/src/android/media/cts/MediaStubActivity.java
index 48dde25..fc5d459 100644
--- a/tests/tests/media/src/android/media/cts/MediaStubActivity.java
+++ b/tests/tests/media/src/android/media/cts/MediaStubActivity.java
@@ -22,6 +22,7 @@
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
+import android.view.WindowManager;
public class MediaStubActivity extends Activity {
private static final String TAG = "MediaStubActivity";
@@ -31,6 +32,11 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ setTurnScreenOn(true);
+ setShowWhenLocked(true);
+
setContentView(R.layout.mediaplayer);
SurfaceView surfaceV = (SurfaceView)findViewById(R.id.surface);
diff --git a/tests/tests/media/src/android/media/cts/MediaStubActivity2.java b/tests/tests/media/src/android/media/cts/MediaStubActivity2.java
index d16c841..8b9a109 100644
--- a/tests/tests/media/src/android/media/cts/MediaStubActivity2.java
+++ b/tests/tests/media/src/android/media/cts/MediaStubActivity2.java
@@ -23,6 +23,7 @@
import android.view.SurfaceView;
import android.view.TextureView;
import android.view.TextureView.SurfaceTextureListener;
+import android.view.WindowManager;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@@ -36,6 +37,11 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ setTurnScreenOn(true);
+ setShowWhenLocked(true);
+
setContentView(R.layout.mediacodecplayer);
SurfaceView surfaceV = (SurfaceView)findViewById(R.id.surface);
diff --git a/tests/tests/media/src/android/media/cts/SoundPoolTest.java b/tests/tests/media/src/android/media/cts/SoundPoolTest.java
index e4df4ac..c345816 100644
--- a/tests/tests/media/src/android/media/cts/SoundPoolTest.java
+++ b/tests/tests/media/src/android/media/cts/SoundPoolTest.java
@@ -16,26 +16,32 @@
package android.media.cts;
-import android.media.cts.R;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.SoundPool;
+import android.media.cts.R;
import android.platform.test.annotations.AppModeFull;
-import android.test.AndroidTestCase;
-
+import androidx.test.InstrumentationRegistry;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Arrays;
-import java.util.concurrent.atomic.AtomicInteger;
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
@AppModeFull(reason = "TODO: evaluate and port to instant")
-abstract class SoundPoolTest extends AndroidTestCase {
+@RunWith(JUnitParamsRunner.class)
+abstract class SoundPoolTest {
private static final int SOUNDPOOL_STREAMS = 4;
private static final int PRIORITY = 1;
@@ -71,20 +77,22 @@
return sounds;
}
+ private static Context getContext() {
+ return InstrumentationRegistry.getInstrumentation().getTargetContext();
+ }
+
protected AudioAttributes getAudioAttributes() {
return new AudioAttributes.Builder()
.setLegacyStreamType(AudioManager.STREAM_MUSIC).build();
}
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mFile = new File(mContext.getFilesDir(), getFileName());
+ @Before
+ public void setUp() throws Exception {
+ mFile = new File(getContext().getFilesDir(), getFileName());
}
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
+ @After
+ public void tearDown() throws Exception {
if (mFile.exists()) {
mFile.delete();
}
@@ -95,15 +103,16 @@
}
}
+ @Test
public void testLoad() throws Exception {
mSoundPool = new SoundPool.Builder().setMaxStreams(SOUNDPOOL_STREAMS)
.setAudioAttributes(getAudioAttributes()).build();
- int sampleId1 = mSoundPool.load(mContext, getSoundA(), PRIORITY);
+ int sampleId1 = mSoundPool.load(getContext(), getSoundA(), PRIORITY);
waitUntilLoaded(sampleId1);
// should return true, but returns false
mSoundPool.unload(sampleId1);
- AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(getSoundCs());
+ AssetFileDescriptor afd = getContext().getResources().openRawResourceFd(getSoundCs());
int sampleId2;
sampleId2 = mSoundPool.load(afd, PRIORITY);
waitUntilLoaded(sampleId2);
@@ -129,7 +138,7 @@
FileOutputStream fOutput = null;
try {
fOutput = new FileOutputStream(f);
- InputStream is = mContext.getResources().openRawResource(getSoundA());
+ InputStream is = getContext().getResources().openRawResource(getSoundA());
byte[] buffer = new byte[1024];
int length = is.read(buffer);
while (length != -1) {
@@ -144,8 +153,14 @@
}
}
- public void testSoundPoolOp() throws Exception {
- mSoundPool = new SoundPool.Builder().setMaxStreams(SOUNDPOOL_STREAMS)
+ /**
+ * Parameterized tests consider 1, 2, 4 streams in the SoundPool.
+ */
+
+ @Test
+ @Parameters({"1", "2", "4"})
+ public void testSoundPoolOp(int streamCount) throws Exception {
+ mSoundPool = new SoundPool.Builder().setMaxStreams(streamCount)
.setAudioAttributes(getAudioAttributes()).build();
int sampleID = loadSampleSync(getSoundA(), PRIORITY);
@@ -187,8 +202,10 @@
mSoundPool.unload(sampleID);
}
- public void testMultiSound() throws Exception {
- mSoundPool = new SoundPool.Builder().setMaxStreams(SOUNDPOOL_STREAMS)
+ @Test
+ @Parameters({"1", "2", "4"})
+ public void testMultiSound(int streamCount) throws Exception {
+ mSoundPool = new SoundPool.Builder().setMaxStreams(streamCount)
.setAudioAttributes(getAudioAttributes()).build();
int sampleID1 = loadSampleSync(getSoundA(), PRIORITY);
int sampleID2 = loadSampleSync(getSoundCs(), PRIORITY);
@@ -217,8 +234,10 @@
mSoundPool = null;
}
- public void testLoadMore() throws Exception {
- mSoundPool = new SoundPool.Builder().setMaxStreams(SOUNDPOOL_STREAMS)
+ @Test
+ @Parameters({"1", "2", "4"})
+ public void testLoadMore(int streamCount) throws Exception {
+ mSoundPool = new SoundPool.Builder().setMaxStreams(streamCount)
.setAudioAttributes(getAudioAttributes()).build();
int[] sounds = getSounds();
int[] soundIds = new int[sounds.length];
@@ -241,6 +260,7 @@
mSoundPool.release();
}
+ @Test
public void testAutoPauseResume() throws Exception {
// The number of possible SoundPool streams simultaneously active is limited by
// track resources. Generally this is no greater than 32, but the actual
@@ -283,7 +303,7 @@
// initiate loading
final int[] soundIds = new int[TEST_STREAMS];
for (int i = 0; i < soundIds.length; i++) {
- soundIds[i] = soundPool.load(mContext, sounds[i % sounds.length], PRIORITY);
+ soundIds[i] = soundPool.load(getContext(), sounds[i % sounds.length], PRIORITY);
}
// wait for all sounds to load,
@@ -346,7 +366,7 @@
* @throws InterruptedException
*/
private int loadSampleSync(int sampleId, int prio) throws InterruptedException {
- int sample = mSoundPool.load(mContext, sampleId, prio);
+ int sample = mSoundPool.load(getContext(), sampleId, prio);
waitUntilLoaded(sample);
return sample;
}
diff --git a/tests/tests/mediaparser/AndroidTest.xml b/tests/tests/mediaparser/AndroidTest.xml
index f3d66cd..e670a80 100644
--- a/tests/tests/mediaparser/AndroidTest.xml
+++ b/tests/tests/mediaparser/AndroidTest.xml
@@ -19,6 +19,7 @@
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.media.apex" />
<object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk30ModuleController" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/tests/mediaparser/TEST_MAPPING b/tests/tests/mediaparser/TEST_MAPPING
index 3d21914..b871ae5 100644
--- a/tests/tests/mediaparser/TEST_MAPPING
+++ b/tests/tests/mediaparser/TEST_MAPPING
@@ -1,4 +1,9 @@
{
+ "mainline-presubmit": [
+ {
+ "name": "CtsMediaParserTestCases[com.google.android.media.apex]"
+ }
+ ],
"presubmit": [
{
"name": "CtsMediaParserTestCases"
diff --git a/tests/tests/mediastress/OWNERS b/tests/tests/mediastress/OWNERS
new file mode 100644
index 0000000..eb1063e
--- /dev/null
+++ b/tests/tests/mediastress/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 1344
+include ../../media/OWNERS
diff --git a/tests/tests/nativemedia/aaudio/Android.mk b/tests/tests/nativemedia/aaudio/Android.mk
index ed3814d..8f099f5 100644
--- a/tests/tests/nativemedia/aaudio/Android.mk
+++ b/tests/tests/nativemedia/aaudio/Android.mk
@@ -17,6 +17,8 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsNativeMediaAAudioTestCases
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
# Include both the 32 and 64 bit versions
LOCAL_MULTILIB := both
diff --git a/tests/tests/nativemidi/Android.mk b/tests/tests/nativemidi/Android.mk
index 8c628bc..8b91117 100755
--- a/tests/tests/nativemidi/Android.mk
+++ b/tests/tests/nativemidi/Android.mk
@@ -36,6 +36,8 @@
# Must match the package name in CtsTestCaseList.mk
LOCAL_PACKAGE_NAME := CtsNativeMidiTestCases
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_MULTILIB := both
LOCAL_SDK_VERSION := current
diff --git a/tests/tests/neuralnetworks/Android.mk b/tests/tests/neuralnetworks/Android.mk
index 019672c..ff5317a 100644
--- a/tests/tests/neuralnetworks/Android.mk
+++ b/tests/tests/neuralnetworks/Android.mk
@@ -38,6 +38,7 @@
LOCAL_SDK_VERSION := current
LOCAL_NDK_STL_VARIANT := c++_static
+LOCAL_MIN_SDK_VERSION := 30
include $(BUILD_CTS_EXECUTABLE)
diff --git a/tests/tests/neuralnetworks/AndroidManifest.xml b/tests/tests/neuralnetworks/AndroidManifest.xml
new file mode 100644
index 0000000..de2efbd
--- /dev/null
+++ b/tests/tests/neuralnetworks/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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.neuralnetworks">
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="31" />
+</manifest>
+
diff --git a/tests/tests/neuralnetworks/AndroidTest.xml b/tests/tests/neuralnetworks/AndroidTest.xml
index 6ec4752..b89d563 100644
--- a/tests/tests/neuralnetworks/AndroidTest.xml
+++ b/tests/tests/neuralnetworks/AndroidTest.xml
@@ -19,6 +19,7 @@
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.neuralnetworks.apex" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="cleanup" value="true" />
<option name="push" value="CtsNNAPITestCases->/data/local/tmp/CtsNNAPITestCases" />
diff --git a/tests/tests/neuralnetworks/benchmark/Android.mk b/tests/tests/neuralnetworks/benchmark/Android.mk
index dd69c5e..dfa3131 100644
--- a/tests/tests/neuralnetworks/benchmark/Android.mk
+++ b/tests/tests/neuralnetworks/benchmark/Android.mk
@@ -17,6 +17,8 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsNNAPIBenchmarkTestCases
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
# Don't include this package in any target
LOCAL_MODULE_TAGS := optional
@@ -36,6 +38,6 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_ASSET_DIR := test/mlts/models/assets
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 30
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java b/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java
index 2c860ad..c6ad0dc 100644
--- a/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java
+++ b/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java
@@ -93,23 +93,28 @@
@Test
@LargeTest
public void testNNAPI() throws BenchmarkException, IOException {
- if (!NNTestBase.hasAccelerator()) { // Skip.
- return;
- }
+ List<String> accelerators = new ArrayList<>();
+ NNTestBase.getAcceleratorNames(accelerators);
+ for (String accelerator : accelerators) {
+ if (accelerator.equals("nnapi-reference")) { // Skip.
+ continue;
+ }
- try (NNTestBase test = mModel.createNNTestBase(/*useNNAPI=*/true,
- /*enableIntermediateTensorsDump=*/false)) {
- test.setupModel(mActivity);
- Pair<List<InferenceInOutSequence>, List<InferenceResult>> inferenceResults =
- test.runBenchmarkCompleteInputSet(/*setRepeat=*/1, /*timeoutSec=*/3600);
- BenchmarkResult benchmarkResult =
- BenchmarkResult.fromInferenceResults(
- mModel.mModelName,
- BenchmarkResult.BACKEND_TFLITE_NNAPI,
- inferenceResults.first,
- inferenceResults.second,
- test.getEvaluator());
- assertFalse(benchmarkResult.hasValidationErrors());
+ try (NNTestBase test = mModel.createNNTestBase(/*useNNAPI=*/true,
+ /*enableIntermediateTensorsDump=*/false)) {
+ test.setNNApiDeviceName(accelerator);
+ test.setupModel(mActivity);
+ Pair<List<InferenceInOutSequence>, List<InferenceResult>> inferenceResults =
+ test.runBenchmarkCompleteInputSet(/*setRepeat=*/1, /*timeoutSec=*/3600);
+ BenchmarkResult benchmarkResult =
+ BenchmarkResult.fromInferenceResults(
+ mModel.mModelName,
+ BenchmarkResult.BACKEND_TFLITE_NNAPI,
+ inferenceResults.first,
+ inferenceResults.second,
+ test.getEvaluator());
+ assertFalse(benchmarkResult.hasValidationErrors());
+ }
}
}
}
diff --git a/tests/tests/neuralnetworks/tflite_delegate/Android.mk b/tests/tests/neuralnetworks/tflite_delegate/Android.mk
index 0fbc8e1..eb6f2c88 100644
--- a/tests/tests/neuralnetworks/tflite_delegate/Android.mk
+++ b/tests/tests/neuralnetworks/tflite_delegate/Android.mk
@@ -23,6 +23,7 @@
tensorflow/lite/delegates/nnapi/nnapi_delegate_test.cc \
tensorflow/lite/kernels/test_util.cc \
tensorflow/core/platform/default/logging.cc \
+ tensorflow/core/platform/default/env_time.cc \
tensorflow/lite/kernels/acceleration_test_util.cc \
tensorflow/lite/kernels/acceleration_test_util_internal.cc \
tensorflow/lite/delegates/nnapi/acceleration_test_list.cc \
@@ -31,6 +32,7 @@
LOCAL_C_INCLUDES += external/flatbuffers/include
LOCAL_C_INCLUDES += external/tensorflow
+LOCAL_C_INCLUDES += external/ruy
LOCAL_CFLAGS := \
-DPLATFORM_POSIX_ANDROID \
@@ -44,7 +46,7 @@
LOCAL_SHARED_LIBRARIES := libandroid liblog libneuralnetworks
LOCAL_STATIC_LIBRARIES := libgtest_ndk_c++ libgmock_ndk libtflite_static
-LOCAL_HEADER_LIBRARIES := libeigen gemmlowp_headers
+LOCAL_HEADER_LIBRARIES := libeigen gemmlowp_headers libtflite_schema_headers
LOCAL_SDK_VERSION := current
LOCAL_NDK_STL_VARIANT := c++_static
include $(BUILD_STATIC_LIBRARY)
diff --git a/tests/tests/nfc/src/android/nfc/cts/NfcPreferredPaymentTest.java b/tests/tests/nfc/src/android/nfc/cts/NfcPreferredPaymentTest.java
index c55edc4..193b029 100644
--- a/tests/tests/nfc/src/android/nfc/cts/NfcPreferredPaymentTest.java
+++ b/tests/tests/nfc/src/android/nfc/cts/NfcPreferredPaymentTest.java
@@ -116,4 +116,33 @@
}
}
+ /** Tests getSelectionModeForCategory API
+ * CardEmulation.CATEGORY_PAYMENT */
+ @Test
+ public void testGetSelectionModeForCategoryPayment() {
+ try {
+ int mode = mCardEmulation.getSelectionModeForCategory(CardEmulation.CATEGORY_PAYMENT);
+ Log.i(mTag, "getSelectionModeForCategory for Payment: " + mode);
+
+ assertTrue("Retrieve incorrect SelectionMode for Payment",
+ CardEmulation.SELECTION_MODE_PREFER_DEFAULT == mode);
+ } catch (Exception e) {
+ fail("Unexpected Exception " + e);
+ }
+ }
+
+ /** Tests getSelectionModeForCategory API
+ * CardEmulation.CATEGORY_OTHER */
+ @Test
+ public void testGetSelectionModeForCategoryOther() {
+ try {
+ int mode = mCardEmulation.getSelectionModeForCategory(CardEmulation.CATEGORY_OTHER);
+ Log.i(mTag, "getSelectionModeForCategory for Other: " + mode);
+
+ assertTrue("Retrieve incorrect SelectionMode for Other",
+ CardEmulation.SELECTION_MODE_ASK_IF_CONFLICT == mode);
+ } catch (Exception e) {
+ fail("Unexpected Exception " + e);
+ }
+ }
}
diff --git a/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
index f5606de..3f93fb5 100644
--- a/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
+++ b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
@@ -35,6 +35,7 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.UiAutomation;
+import android.content.pm.PackageManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -238,21 +239,28 @@
@Test
public void testResetListenerHints_singleListener() throws Exception {
- toggleListenerAccess(TestNotificationListener.getId(),
- InstrumentationRegistry.getInstrumentation(), true);
- Thread.sleep(500); // wait for listener to be allowed
+ int conditionValue = 0;
+ int condition = NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
- mListener = TestNotificationListener.getInstance();
- Assert.assertNotNull(mListener);
+ toggleListenerAccess(
+ TestNotificationListener.getId(), InstrumentationRegistry.getInstrumentation(), true);
+ Thread.sleep(500); // wait for listener to be allowed
- mListener.requestListenerHints(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
+ mListener = TestNotificationListener.getInstance();
+ Assert.assertNotNull(mListener);
+ /*In case of wear os we have some default disable listener registered*/
+ if (isWatch()) {
+ condition |= NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
+ conditionValue = mListener.getCurrentListenerHints();
+ }
- assertEquals(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS,
- mListener.getCurrentListenerHints());
+ mListener.requestListenerHints(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
- mListener.clearRequestedListenerHints();
+ assertEquals(condition, mListener.getCurrentListenerHints());
- assertEquals(0, mListener.getCurrentListenerHints());
+ mListener.clearRequestedListenerHints();
+
+ assertEquals(conditionValue, mListener.getCurrentListenerHints());
}
@Test
@@ -278,8 +286,11 @@
mListener.getCurrentListenerHints());
mSecondaryListener.clearRequestedListenerHints();
- assertEquals(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS,
- mSecondaryListener.getCurrentListenerHints());
+ /*In case of wear os we have some default disable listener registered*/
+ if (!isWatch()) {
+ assertEquals(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS,
+ mSecondaryListener.getCurrentListenerHints());
+ }
}
@Test
@@ -385,4 +396,8 @@
uiAutomation.destroy();
}
}
+
+ private boolean isWatch() {
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+ }
}
diff --git a/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java b/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java
index 4318f7f..e83928a 100644
--- a/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java
+++ b/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java
@@ -23,6 +23,7 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
import android.app.Instrumentation;
import android.app.Notification;
@@ -71,7 +72,7 @@
final String TAG = "NotAsstServiceTest";
final String NOTIFICATION_CHANNEL_ID = "NotificationAssistantServiceTest";
final int ICON_ID = android.R.drawable.sym_def_app_icon;
- final long SLEEP_TIME = 500; // milliseconds
+ final long SLEEP_TIME = 1000; // milliseconds
private TestNotificationAssistant mNotificationAssistantService;
private TestNotificationListener mNotificationListenerService;
@@ -80,6 +81,10 @@
private Context mContext;
private UiAutomation mUi;
+ private boolean isWatch() {
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+ }
+
@Before
public void setUp() throws IOException {
mUi = InstrumentationRegistry.getInstrumentation().getUiAutomation();
@@ -557,6 +562,7 @@
if (isTelevision()) {
return;
}
+ assumeFalse("Status bar service not supported", isWatch());
setUpListeners();
turnScreenOn();
mUi.adoptShellPermissionIdentity("android.permission.EXPAND_STATUS_BAR");
@@ -588,6 +594,7 @@
if (isTelevision()) {
return;
}
+ assumeFalse("Status bar service not supported", isWatch());
setUpListeners();
turnScreenOn();
mUi.adoptShellPermissionIdentity("android.permission.EXPAND_STATUS_BAR");
@@ -613,6 +620,7 @@
if (isTelevision()) {
return;
}
+ assumeFalse("Status bar service not supported", isWatch());
setUpListeners();
turnScreenOn();
mUi.adoptShellPermissionIdentity("android.permission.EXPAND_STATUS_BAR");
diff --git a/tests/tests/os/CtsOsTestCases.xml b/tests/tests/os/CtsOsTestCases.xml
index 1d4b393..e80d897 100644
--- a/tests/tests/os/CtsOsTestCases.xml
+++ b/tests/tests/os/CtsOsTestCases.xml
@@ -23,16 +23,6 @@
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsOsTestCases.apk" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="force-install-mode" value="FULL"/>
- <option name="test-file-name" value="CtsMockInputMethod.apk" />
- </target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
- <option name="force-skip-system-props" value="true" />
- <option name="screen-always-on" value="on" />
- </target_preparer>
-
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.os.cts" />
<option name="runtime-hint" value="3m15s" />
diff --git a/tests/tests/os/OWNERS b/tests/tests/os/OWNERS
index 3429892..c748b28 100644
--- a/tests/tests/os/OWNERS
+++ b/tests/tests/os/OWNERS
@@ -1,4 +1,5 @@
-per-file *AutoRevoke* = eugenesusla@google.com
-per-file *Companion* = eugenesusla@google.com
-per-file *AndroidManifest.xml = eugenesusla@google.com
-per-file *CtsOsTestCases.xml = eugenesusla@google.com
+per-file *AutoRevoke* = file:platform/frameworks/base:/core/java/android/permission/OWNERS
+per-file *AppHibernation* = file:platform/frameworks/base:/core/java/android/permission/OWNERS
+per-file *Companion* = file:platform/frameworks/base:/core/java/android/permission/OWNERS
+per-file *AndroidManifest.xml = file:platform/frameworks/base:/core/java/android/permission/OWNERS
+per-file *CtsOsTestCases.xml = file:platform/frameworks/base:/core/java/android/permission/OWNERS
diff --git a/tests/tests/os/UffdGc/Android.bp b/tests/tests/os/UffdGc/Android.bp
new file mode 100644
index 0000000..8ef4d9a
--- /dev/null
+++ b/tests/tests/os/UffdGc/Android.bp
@@ -0,0 +1,51 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsUffdGcTestCases",
+ defaults: ["cts_defaults"],
+ compile_multilib: "both",
+ srcs: ["src/**/*.java"],
+ jni_libs: ["libuserfaultfdtest"],
+ sdk_version: "current",
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ "ctstestrunner-axt",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ test_suites: [
+ "cts",
+ "vts",
+ "general-tests",
+ ],
+}
+
+cc_test_library {
+ name: "libuserfaultfdtest",
+ defaults: ["libctsos_jni_defaults"],
+ srcs: ["jni/android_os_cts_uffdgc_UserfaultfdTest.cc"],
+ stl: "c++_static",
+ sdk_version: "current",
+}
diff --git a/tests/tests/os/UffdGc/AndroidManifest.xml b/tests/tests/os/UffdGc/AndroidManifest.xml
new file mode 100644
index 0000000..8d7f12e
--- /dev/null
+++ b/tests/tests/os/UffdGc/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.os.cts.uffdgc">
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.os.cts.uffdgc"
+ android:label="CTS tests of userfaultfd-based GC">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+</manifest>
+
diff --git a/tests/tests/os/UffdGc/AndroidTest.xml b/tests/tests/os/UffdGc/AndroidTest.xml
new file mode 100644
index 0000000..48e9869
--- /dev/null
+++ b/tests/tests/os/UffdGc/AndroidTest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs CTS tests of userfaultfd-based GC.">
+ <option name="config-descriptor:metadata" key="component" value="art" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <option name="test-suite-tag" value="cts" />
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController">
+ <option name="min-api-level" value="31" />
+ </object>
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsUffdGcTestCases.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.os.cts.uffdgc" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git a/tests/tests/os/UffdGc/OWNERS b/tests/tests/os/UffdGc/OWNERS
new file mode 100644
index 0000000..37794e7
--- /dev/null
+++ b/tests/tests/os/UffdGc/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 44922
+lokeshgidra@google.com
diff --git a/tests/tests/os/UffdGc/jni/android_os_cts_uffdgc_UserfaultfdTest.cc b/tests/tests/os/UffdGc/jni/android_os_cts_uffdgc_UserfaultfdTest.cc
new file mode 100644
index 0000000..d540753
--- /dev/null
+++ b/tests/tests/os/UffdGc/jni/android_os_cts_uffdgc_UserfaultfdTest.cc
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "jni.h"
+
+#include <cstring>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/userfaultfd.h>
+#include <poll.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <syscall.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+static int page_sz = 0;
+static bool perform_tests = true;
+
+static void* userfault_handler_thread(void* arg) {
+ int uffd = reinterpret_cast<intptr_t>(arg);
+ struct uffd_msg msg;
+ struct uffdio_copy uffdio_copy;
+ ssize_t nread;
+ int ret = 0;
+ char* page = static_cast<char*>(mmap(nullptr, page_sz, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+ if (page == MAP_FAILED) {
+ ret = errno;
+ goto out;
+ }
+ std::memset(&msg, '\0', sizeof msg);
+ std::memset(&uffdio_copy, '\0', sizeof uffdio_copy);
+ std::memset(page, 'a', page_sz);
+
+ // Loop, handling incoming events on the userfaultfd file descriptor
+ do {
+ // poll on uffd waiting for an event
+ struct pollfd pollfd;
+ int nready;
+ pollfd.fd = uffd;
+ pollfd.events = POLLIN;
+ nready = poll(&pollfd, 1, -1);
+ if (nready == -1) {
+ ret = errno;
+ break;
+ }
+
+ /* Read an event from the userfaultfd */
+ nread = read(uffd, &msg, sizeof(msg));
+ // EOF on userfaultfd
+ if (nread == 0) {
+ ret = -1;
+ break;
+ }
+
+ if (nread == -1) {
+ ret = errno;
+ break;
+ }
+
+ // We expect only one kind of event; verify that assumption
+ if (msg.event != UFFD_EVENT_PAGEFAULT) {
+ ret = -1;
+ break;
+ }
+ uffdio_copy.src = reinterpret_cast<size_t>(page);
+
+ // Align fault address to page boundary
+ uffdio_copy.dst = msg.arg.pagefault.address & ~(page_sz - 1);
+ uffdio_copy.len = page_sz;
+ uffdio_copy.mode = 0; // Wake-up thread thread waiting for page-fault resolution
+ uffdio_copy.copy = 0; // Used by kernel to return how many bytes copied
+ if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) < 0) {
+ ret = errno;
+ break;
+ }
+ } while (false);
+ munmap(page, page_sz);
+out:
+ pthread_exit(reinterpret_cast<void*>(ret));
+}
+
+extern "C" JNIEXPORT void JNICALL Java_android_os_cts_uffdgc_UserfaultfdTest_setUpUserfaultfd(JNIEnv*) {
+#if defined(__linux__)
+ static constexpr int kRequiredMajor = 5;
+ static constexpr int kRequiredMinor = 4;
+
+ int major, minor;
+ struct utsname uts;
+ if (uname(&uts) != 0 ||
+ strcmp(uts.sysname, "Linux") != 0 ||
+ sscanf(uts.release, "%d.%d", &major, &minor) != 2 ||
+ (major < kRequiredMajor || (major == kRequiredMajor && minor < kRequiredMinor))) {
+ perform_tests = false;
+ }
+#else
+ perform_tests = false;
+#endif
+ page_sz = sysconf(_SC_PAGE_SIZE);
+}
+
+extern "C"
+JNIEXPORT jint JNICALL Java_android_os_cts_uffdgc_UserfaultfdTest_performKernelSpaceUffd(JNIEnv*) {
+ if (!perform_tests) {
+ return 0;
+ }
+ int ret = 0, write_fd = 0;
+ void* addr = nullptr;
+ pthread_t thr; // ID of thread that handles page faults
+ struct uffdio_register uffdio_register;
+ int uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY);
+ if (uffd < 0) {
+ ret = errno;
+ goto out;
+ }
+
+ write_fd = memfd_create("ReadFrom", MFD_CLOEXEC);
+ if (write_fd == -1) {
+ ret = errno;
+ goto out_close_uffd;
+ }
+ if (ftruncate(write_fd, page_sz) == -1) {
+ ret = errno;
+ goto out_close_both;
+ }
+
+ /* Create a private anonymous mapping. The memory will be
+ * demand-zero paged--that is, not yet allocated. When we
+ * actually touch the memory, it will be allocated via
+ * the userfaultfd.
+ */
+ addr = mmap(nullptr, page_sz, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (addr == MAP_FAILED) {
+ ret = errno;
+ goto out_close_both;
+ }
+
+ struct uffdio_api api;
+ std::memset(&api, '\0', sizeof api);
+ api.api = UFFD_API;
+ if (ioctl(uffd, UFFDIO_API, &api) < 0) {
+ ret = errno;
+ goto out_unmap;
+ }
+
+ /* Register the memory range of the mapping we just created for
+ * handling by the userfaultfd object. In mode, we request to track
+ * missing pages (i.e., pages that have not yet been faulted in).
+ */
+ std::memset(&uffdio_register, '\0', sizeof uffdio_register);
+ uffdio_register.range.start = reinterpret_cast<size_t>(addr);
+ uffdio_register.range.len = page_sz;
+ uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
+ if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) < 0) {
+ ret = errno;
+ goto out_unmap;
+ }
+
+ // Create a thread that will process the userfaultfd events
+ ret = pthread_create(&thr, nullptr, userfault_handler_thread, reinterpret_cast<void*>(uffd));
+ if (ret != 0) {
+ goto out_unmap;
+ }
+
+ // The write is expected to fail as the buffer starting at addr doesn't have a
+ // page pinned, and when the syscall will try to read from it, will trigger a
+ // userfault. But only user-mode faults are allowed.
+ if (write(write_fd, addr, page_sz) >= 0) {
+ ret = -1;
+ } else {
+ ret = errno;
+ }
+
+ // Invoke a userfault so that the handler thread then exit normally.
+ static_cast<char*>(addr)[42] = 'a';
+
+ pthread_join(thr, nullptr);
+out_unmap:
+ munmap(addr, page_sz);
+out_close_both:
+ close(write_fd);
+out_close_uffd:
+ close(uffd);
+out:
+ return ret;
+}
+
+// Invoking userfaultfd without USER_MODE_ONLY by a process without CAP_SYS_PTRACE
+// should not be permitted.
+extern "C" JNIEXPORT jint JNICALL Java_android_os_cts_uffdgc_UserfaultfdTest_performUffdWithoutUserModeOnly(JNIEnv*) {
+ if (!perform_tests) {
+ return 0;
+ }
+ int uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
+ if (uffd < 0) {
+ return errno;
+ } else {
+ close(uffd);
+ }
+ return 0;
+}
+
+extern "C" JNIEXPORT jint JNICALL Java_android_os_cts_uffdgc_UserfaultfdTest_performMremapDontUnmap(JNIEnv*) {
+ int ret = 0;
+ if (!perform_tests) {
+ return 0;
+ }
+ void* old = mmap(nullptr, page_sz, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+ if (old == MAP_FAILED ||
+ mremap(old, page_sz, page_sz, MREMAP_MAYMOVE | MREMAP_DONTUNMAP, nullptr) == MAP_FAILED) {
+ ret = errno;
+ }
+ return ret;
+}
+
+extern "C" JNIEXPORT jint JNICALL Java_android_os_cts_uffdgc_UserfaultfdTest_performMinorUffd(JNIEnv*) {
+ int ret = 0;
+ if (!perform_tests) {
+ return 0;
+ }
+ int uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY);
+ if (uffd < 0) {
+ ret = errno;
+ goto out;
+ }
+ struct uffdio_api api;
+ std::memset(&api, '\0', sizeof api);
+ api.api = UFFD_API;
+ // TODO: Remove the following define once its definition is available in
+ // linux/userfaultfd.h header file.
+#ifndef UFFD_FEATURE_MINOR_SHMEM
+#define UFFD_FEATURE_MINOR_SHMEM (1 << 10)
+#endif
+ api.features = UFFD_FEATURE_MINOR_SHMEM;
+ if (ioctl(uffd, UFFDIO_API, &api) < 0) {
+ ret = errno;
+ }
+ close(uffd);
+out:
+ return ret;
+}
diff --git a/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java b/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java
new file mode 100644
index 0000000..e83357c
--- /dev/null
+++ b/tests/tests/os/UffdGc/src/android/os/cts/uffdgc/UserfaultfdTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.os.cts.uffdgc;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import androidx.test.runner.AndroidJUnit4;
+
+@RunWith(AndroidJUnit4.class)
+public final class UserfaultfdTest {
+
+ static {
+ System.loadLibrary("userfaultfdtest");
+ }
+
+ @Before
+ public void setUp() {
+ setUpUserfaultfd();
+ }
+
+ // Test if a userfault from kernel-space fails or not. It is
+ // not allowed for unprivileged processes.
+ @Test
+ public void kernelSpaceUserfault() {
+ // Expect return value to be EFAULT (14).
+ assertEquals(14, performKernelSpaceUffd());
+ }
+
+ // Test if a userfault file descriptor can be obtained without
+ // UFFD_USER_MODE_ONLY flag. Unprivileged processes must specify
+ // this flag to forbid kernel-space userfaults.
+ @Test
+ public void nonUserModeOnlyUserfaultfd() {
+ // Expect return value to be EPERM (1).
+ assertEquals(1, performUffdWithoutUserModeOnly());
+ }
+
+ // Test if mremap syscall on a non-anonymous shared mapping
+ // using MREMAP_DONTUNMAP flag works.
+ @Test
+ public void mremapDontUnmap() {
+ assertEquals(0, performMremapDontUnmap());
+ }
+
+ // Test if userfaultfd works for minor-faults on shmem.
+ @Test
+ public void minorUserfaultfd() {
+ assertEquals(0, performMinorUffd());
+ }
+
+ private native void setUpUserfaultfd();
+ private native int performKernelSpaceUffd();
+ private native int performUffdWithoutUserModeOnly();
+ private native int performMremapDontUnmap();
+ private native int performMinorUffd();
+}
diff --git a/tests/tests/os/assets/platform_versions.txt b/tests/tests/os/assets/platform_versions.txt
index 3762249..f53859b 100644
--- a/tests/tests/os/assets/platform_versions.txt
+++ b/tests/tests/os/assets/platform_versions.txt
@@ -1 +1,2 @@
S
+T
diff --git a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
index 44a5444..c77b52a 100644
--- a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
+++ b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
@@ -30,7 +30,10 @@
import android.provider.DeviceConfig
import android.support.test.uiautomator.By
import android.support.test.uiautomator.BySelector
+import android.support.test.uiautomator.UiDevice
import android.support.test.uiautomator.UiObject2
+import android.support.test.uiautomator.UiScrollable
+import android.support.test.uiautomator.UiSelector
import android.view.accessibility.AccessibilityNodeInfo
import android.widget.Switch
import androidx.test.InstrumentationRegistry
@@ -76,6 +79,7 @@
private val context: Context = InstrumentationRegistry.getTargetContext()
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val uiDevice: UiDevice = UiDevice.getInstance(instrumentation)
private val mPermissionControllerResources: Resources = context.createPackageContext(
context.packageManager.permissionControllerPackageName, 0).resources
@@ -244,7 +248,10 @@
// Setup
goToPermissions()
click("Calendar")
- click("Allow")
+ // Wear OS uses a switch and does not display a dialog
+ if (!hasFeatureWatch()) {
+ click("Allow")
+ }
Thread.sleep(500)
goBack()
goBack()
@@ -387,11 +394,17 @@
.addFlags(FLAG_ACTIVITY_NEW_TASK))
waitForIdle()
+
click("Permissions")
}
private fun click(label: String) {
- waitFindNode(hasTextThat(containsStringIgnoringCase(label))).click()
+ waitFindObject(byTextIgnoreCase(label)).click()
+ waitForIdle()
+ }
+
+ private fun hasFeatureWatch(): Boolean {
+ return context.packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)
}
private fun assertWhitelistState(state: Boolean) {
diff --git a/tests/tests/os/src/android/os/cts/BuildTest.java b/tests/tests/os/src/android/os/cts/BuildTest.java
index b0a1a5e..efe3c12 100644
--- a/tests/tests/os/src/android/os/cts/BuildTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildTest.java
@@ -348,6 +348,7 @@
public void testIsSecureUserBuild() throws IOException {
assertEquals("Must be a user build", "user", Build.TYPE);
assertProperty("Must be a non-debuggable build", RO_DEBUGGABLE, "0");
+ assertFalse("Must be a non-debuggable build", Build.isDebuggable());
assertProperty("Must be a secure build", RO_SECURE, "1");
}
diff --git a/tests/tests/os/src/android/os/cts/SimpleTestActivity.java b/tests/tests/os/src/android/os/cts/SimpleTestActivity.java
index 22c706fe..3acbce6 100644
--- a/tests/tests/os/src/android/os/cts/SimpleTestActivity.java
+++ b/tests/tests/os/src/android/os/cts/SimpleTestActivity.java
@@ -16,30 +16,6 @@
package android.os.cts;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE;
-
import android.app.Activity;
-import android.os.Bundle;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-public class SimpleTestActivity extends Activity {
- private EditText mEditText;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- mEditText = new EditText(this);
- final LinearLayout layout = new LinearLayout(this);
- layout.setOrientation(LinearLayout.VERTICAL);
- layout.addView(mEditText);
- setContentView(layout);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- getWindow().setSoftInputMode(SOFT_INPUT_STATE_ALWAYS_VISIBLE);
- mEditText.requestFocus();
- }
-}
\ No newline at end of file
+public class SimpleTestActivity extends Activity {}
\ No newline at end of file
diff --git a/tests/tests/os/src/android/os/cts/StrictModeTest.java b/tests/tests/os/src/android/os/cts/StrictModeTest.java
index 562fc5e..f0358bd 100644
--- a/tests/tests/os/src/android/os/cts/StrictModeTest.java
+++ b/tests/tests/os/src/android/os/cts/StrictModeTest.java
@@ -17,15 +17,9 @@
package android.os.cts;
import static android.content.Context.WINDOW_SERVICE;
-import static android.content.pm.PackageManager.FEATURE_INPUT_METHODS;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-import static com.android.cts.mockime.ImeEventStreamTestUtils.clearAllEvents;
-import static com.android.cts.mockime.ImeEventStreamTestUtils.expectCommand;
-import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEvent;
-import static com.android.cts.mockime.ImeEventStreamTestUtils.notExpectEvent;
-
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -38,9 +32,7 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
-import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
-import android.inputmethodservice.InputMethodService;
import android.net.TrafficStats;
import android.net.Uri;
import android.os.IBinder;
@@ -69,16 +61,10 @@
import android.view.ViewConfiguration;
import android.view.WindowManager;
-import androidx.annotation.IntDef;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import com.android.cts.mockime.ImeEvent;
-import com.android.cts.mockime.ImeEventStream;
-import com.android.cts.mockime.ImeSettings;
-import com.android.cts.mockime.MockImeSession;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -90,8 +76,6 @@
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.URL;
@@ -110,52 +94,10 @@
public class StrictModeTest {
private static final String TAG = "StrictModeTest";
private static final String REMOTE_SERVICE_ACTION = "android.app.REMOTESERVICE";
- private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(10); // 10 seconds
- private static final long NOT_EXPECT_TIMEOUT = TimeUnit.SECONDS.toMillis(2);
private StrictMode.ThreadPolicy mThreadPolicy;
private StrictMode.VmPolicy mVmPolicy;
- // TODO(b/160143006): re-enable IMS part test.
- private static final boolean DISABLE_VERIFY_IMS = false;
-
- /**
- * Verify mode to verifying if APIs violates incorrect context violation.
- *
- * @see #VERIFY_MODE_GET_DISPLAY
- * @see #VERIFY_MODE_GET_WINDOW_MANAGER
- * @see #VERIFY_MODE_GET_VIEW_CONFIGURATION
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {
- VERIFY_MODE_GET_DISPLAY,
- VERIFY_MODE_GET_WINDOW_MANAGER,
- VERIFY_MODE_GET_VIEW_CONFIGURATION,
- })
- private @interface VerifyMode {}
-
- /**
- * Verifies if {@link Context#getDisplay} from {@link InputMethodService} and context created
- * from {@link InputMethodService#createConfigurationContext(Configuration)} violates
- * incorrect context violation.
- */
- private static final int VERIFY_MODE_GET_DISPLAY = 1;
- /**
- * Verifies if get {@link android.view.WindowManager} from {@link InputMethodService} and
- * context created from {@link InputMethodService#createConfigurationContext(Configuration)}
- * violates incorrect context violation.
- *
- * @see Context#getSystemService(String)
- * @see Context#getSystemService(Class)
- */
- private static final int VERIFY_MODE_GET_WINDOW_MANAGER = 2;
- /**
- * Verifies if passing {@link InputMethodService} and context created
- * from {@link InputMethodService#createConfigurationContext(Configuration)} to
- * {@link android.view.ViewConfiguration#get(Context)} violates incorrect context violation.
- */
- private static final int VERIFY_MODE_GET_VIEW_CONFIGURATION = 3;
-
private Context getContext() {
return ApplicationProvider.getApplicationContext();
}
@@ -707,9 +649,6 @@
final Activity activity = InstrumentationRegistry.getInstrumentation()
.startActivitySync(intent);
assertNoViolation(() -> activity.getSystemService(WINDOW_SERVICE));
-
- // TODO(b/159593676): move the logic to CtsInputMethodTestCases
- verifyIms(VERIFY_MODE_GET_WINDOW_MANAGER);
}
@Test
@@ -737,8 +676,6 @@
.startActivitySync(intent);
assertNoViolation(() -> activity.getDisplay());
- // TODO(b/159593676): move the logic to CtsInputMethodTestCases
- verifyIms(VERIFY_MODE_GET_DISPLAY);
try {
getContext().getApplicationContext().getDisplay();
} catch (UnsupportedOperationException e) {
@@ -776,57 +713,6 @@
final Activity activity = InstrumentationRegistry.getInstrumentation()
.startActivitySync(intent);
assertNoViolation(() -> ViewConfiguration.get(activity));
-
- // TODO(b/159593676): move the logic to CtsInputMethodTestCases
- verifyIms(VERIFY_MODE_GET_VIEW_CONFIGURATION);
- }
-
- // TODO(b/159593676): move the logic to CtsInputMethodTestCases
- /**
- * Verify if APIs violates incorrect context violations by {@code mode}.
- *
- * @see VerifyMode
- */
- private void verifyIms(@VerifyMode int mode) throws Exception {
- // If devices do not support installable IMEs, finish the test gracefully. We don't use
- // assumeTrue here because we do pass some cases, so showing "pass" instead of "skip" makes
- // sense here.
- // TODO(b/160143006): re-enable IMS part test.
- if (!supportsInstallableIme() || DISABLE_VERIFY_IMS) {
- return;
- }
-
- try (final MockImeSession imeSession = MockImeSession.create(getContext(),
- InstrumentationRegistry.getInstrumentation().getUiAutomation(),
- new ImeSettings.Builder().setStrictModeEnabled(true))) {
- final ImeEventStream stream = imeSession.openEventStream();
- expectEvent(stream, event -> "onStartInput".equals(event.getEventName()), TIMEOUT);
- final ImeEventStream forkedStream = clearAllEvents(stream, "onStrictModeViolated");
- final ImeEvent imeEvent;
- switch (mode) {
- case VERIFY_MODE_GET_DISPLAY:
- imeEvent = expectCommand(forkedStream, imeSession.callVerifyGetDisplay(),
- TIMEOUT);
- break;
- case VERIFY_MODE_GET_WINDOW_MANAGER:
- imeEvent = expectCommand(forkedStream, imeSession.callVerifyGetWindowManager(),
- TIMEOUT);
- break;
- case VERIFY_MODE_GET_VIEW_CONFIGURATION:
- imeEvent = expectCommand(forkedStream,
- imeSession.callVerifyGetViewConfiguration(), TIMEOUT);
- break;
- default:
- imeEvent = null;
- }
- assertTrue(imeEvent.getReturnBooleanValue());
- notExpectEvent(stream, event -> "onStrictModeViolated".equals(event.getEventName()),
- NOT_EXPECT_TIMEOUT);
- }
- }
-
- private boolean supportsInstallableIme() {
- return getContext().getPackageManager().hasSystemFeature(FEATURE_INPUT_METHODS);
}
private static void runWithRemoteServiceBound(Context context, Consumer<ISecondary> consumer)
diff --git a/tests/tests/packageinstaller/adminpackageinstaller/OWNERS b/tests/tests/packageinstaller/adminpackageinstaller/OWNERS
index 0ab0d04..7455e48 100644
--- a/tests/tests/packageinstaller/adminpackageinstaller/OWNERS
+++ b/tests/tests/packageinstaller/adminpackageinstaller/OWNERS
@@ -1,3 +1,4 @@
# Bug component: 36137
toddke@google.com
sunnygoyal@google.com
+patb@google.com
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/ExcludeWatch.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/ExcludeWatch.kt
new file mode 100644
index 0000000..20cba14
--- /dev/null
+++ b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/ExcludeWatch.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.packageinstaller.install.cts
+
+import android.content.pm.PackageManager
+import org.junit.Assume.assumeFalse
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+class ExcludeWatch(
+ val motivation: String,
+ val packageManager: PackageManager
+) : TestRule {
+
+ override fun apply(stmt: Statement?, desc: Description?): Statement {
+ return FeatureStatement()
+ }
+
+ inner class FeatureStatement : Statement() {
+ override fun evaluate() {
+ assumeFalse(
+ motivation,
+ packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/ExternalSourcesTestAppOpAllowed.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/ExternalSourcesTestAppOpAllowed.kt
index 3e7cd4a..bdb4b20 100644
--- a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/ExternalSourcesTestAppOpAllowed.kt
+++ b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/ExternalSourcesTestAppOpAllowed.kt
@@ -75,11 +75,13 @@
@Test
fun allowedSourceTestViaIntent() {
+ assumeNotWatch()
allowedSourceTest { startInstallationViaIntent() }
}
@Test
fun allowedSourceTestViaSession() {
+ assumeNotWatch()
allowedSourceTest { startInstallationViaSession() }
}
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/InstallSourceInfoTest.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/InstallSourceInfoTest.kt
index 42fddd8..5396efc 100644
--- a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/InstallSourceInfoTest.kt
+++ b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/InstallSourceInfoTest.kt
@@ -40,6 +40,8 @@
@Test
fun installViaIntent() {
+ assumeNotWatch()
+
val packageInstallerPackageName = getPackageInstallerPackageName()
val installation = startInstallationViaIntent()
@@ -56,6 +58,8 @@
@Test
fun InstallViaSession() {
+ assumeNotWatch()
+
startInstallationViaSession()
clickInstallerUIButton(INSTALL_BUTTON_ID)
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt
index 33a8966..2220893 100644
--- a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt
+++ b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/IntentTest.kt
@@ -49,6 +49,8 @@
*/
@Test
fun confirmInstallation() {
+ assumeNotWatch()
+
val installation = startInstallationViaIntent()
clickInstallerUIButton(INSTALL_BUTTON_ID)
@@ -63,6 +65,8 @@
*/
@Test
fun cancelInstallation() {
+ assumeNotWatch()
+
val installation = startInstallationViaIntent()
clickInstallerUIButton(CANCEL_BUTTON_ID)
@@ -76,6 +80,8 @@
*/
@Test
fun reinstallViaPackageUri() {
+ assumeNotWatch()
+
// Regular install
confirmInstallation()
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/PackageInstallerTestBase.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/PackageInstallerTestBase.kt
index 45eb038..3480142 100644
--- a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/PackageInstallerTestBase.kt
+++ b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/PackageInstallerTestBase.kt
@@ -40,6 +40,8 @@
import com.android.compatibility.common.util.FutureResultActivity
import org.junit.After
import org.junit.Assert
+import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Rule
import java.io.File
@@ -215,4 +217,16 @@
fun uninstallTestPackage() {
uiDevice.executeShellCommand("pm uninstall $TEST_APK_PACKAGE_NAME")
}
+
+ fun assumeWatch() {
+ assumeTrue("Test only valid for watch", hasFeatureWatch())
+ }
+
+ fun assumeNotWatch() {
+ assumeFalse("Installing APKs not supported on watch", hasFeatureWatch())
+ }
+
+ private fun hasFeatureWatch(): Boolean {
+ return pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
+ }
}
diff --git a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/SessionTest.kt b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/SessionTest.kt
index 69096f8..87711e9 100644
--- a/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/SessionTest.kt
+++ b/tests/tests/packageinstaller/install/src/android/packageinstaller/install/cts/SessionTest.kt
@@ -27,6 +27,7 @@
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Assert.fail
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.util.concurrent.TimeUnit
@@ -40,6 +41,9 @@
private val context = InstrumentationRegistry.getTargetContext()
private val pm = context.packageManager
+ @get:Rule
+ val excludeWatch = ExcludeWatch("Installing APKs not supported on watch", pm)
+
/**
* Check that we can install an app via a package-installer session
*/
diff --git a/tests/tests/packageinstaller/nopermission/src/android.packageinstaller.nopermission.cts/NoPermissionTests.kt b/tests/tests/packageinstaller/nopermission/src/android.packageinstaller.nopermission.cts/NoPermissionTests.kt
index 024d1ad..235f589 100644
--- a/tests/tests/packageinstaller/nopermission/src/android.packageinstaller.nopermission.cts/NoPermissionTests.kt
+++ b/tests/tests/packageinstaller/nopermission/src/android.packageinstaller.nopermission.cts/NoPermissionTests.kt
@@ -20,6 +20,7 @@
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.content.pm.PackageManager;
import android.content.pm.PackageInstaller
import android.content.pm.PackageInstaller.EXTRA_STATUS
import android.content.pm.PackageInstaller.STATUS_FAILURE_INVALID
@@ -38,6 +39,12 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.junit.runners.model.Statement
+import org.junit.runner.Description
+import org.junit.Rule
+import org.junit.rules.TestRule
+import org.junit.AssumptionViolatedException
+
import java.io.File
import java.lang.IllegalArgumentException
@@ -62,6 +69,7 @@
private var packageName = context.packageName
private var apkFile = File(context.filesDir, TEST_APK_NAME)
private var uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+ private var isWatch: Boolean = pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
private val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
@@ -75,6 +83,21 @@
}
}
+ @get:Rule
+ val testRule: TestRule = object :TestRule {
+ override fun apply(base: Statement, description: Description?)
+ = NewStatement(base)
+ inner class NewStatement(private val base: Statement) : Statement() {
+ @Throws(Throwable::class)
+ override fun evaluate() {
+ if (isWatch) {
+ throw AssumptionViolatedException("Install/uninstall feature is not supported on WearOs");
+ }
+ base.evaluate()
+ }
+ }
+ }
+
@Before
fun wakeUpScreen() {
if (!uiDevice.isScreenOn) {
diff --git a/tests/tests/packageinstaller/tapjacking/src/android/packageinstaller/tapjacking/cts/TapjackingTest.java b/tests/tests/packageinstaller/tapjacking/src/android/packageinstaller/tapjacking/cts/TapjackingTest.java
index e5fda9b..5aa9c5d 100644
--- a/tests/tests/packageinstaller/tapjacking/src/android/packageinstaller/tapjacking/cts/TapjackingTest.java
+++ b/tests/tests/packageinstaller/tapjacking/src/android/packageinstaller/tapjacking/cts/TapjackingTest.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.net.Uri;
import android.platform.test.annotations.AppModeFull;
import android.support.test.uiautomator.By;
@@ -40,6 +41,11 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.AssumptionViolatedException;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
import java.io.IOException;
@@ -57,13 +63,16 @@
private static final long WAIT_FOR_UI_TIMEOUT = 5000;
- private Context mContext;
+ private Context mContext = InstrumentationRegistry.getTargetContext();
private String mPackageName;
private UiDevice mUiDevice;
+ boolean isWatch = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+
+ @Rule
+ public final RequiredRule mRequiredRule = new RequiredRule(isWatch);
@Before
public void setUp() throws Exception {
- mContext = InstrumentationRegistry.getTargetContext();
mPackageName = mContext.getPackageName();
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
if (!mUiDevice.isScreenOn()) {
@@ -114,4 +123,24 @@
public void tearDown() throws Exception {
mUiDevice.pressHome();
}
+
+ private static final class RequiredRule implements TestRule {
+ boolean mIsWatch;
+ RequiredRule(boolean isWatch) {
+ mIsWatch = isWatch;
+ }
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return new Statement() {
+
+ @Override
+ public void evaluate() throws Throwable {
+ if (mIsWatch) {
+ throw new AssumptionViolatedException("Install/uninstall feature is not supported on WearOs");
+ }
+ base.evaluate();
+ }
+ };
+ }
+ }
}
diff --git a/tests/tests/permission/src/android/permission/cts/NfcPermissionTest.java b/tests/tests/permission/src/android/permission/cts/NfcPermissionTest.java
new file mode 100644
index 0000000..c2eae01
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/NfcPermissionTest.java
@@ -0,0 +1,167 @@
+/*
+ * 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.permission.cts;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.pm.PackageManager;
+import android.nfc.NfcAdapter;
+import android.nfc.NfcAdapter.ControllerAlwaysOnListener;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.concurrent.Executor;
+
+@RunWith(JUnit4.class)
+public final class NfcPermissionTest {
+
+ private NfcAdapter mNfcAdapter;
+
+ private boolean supportsHardware() {
+ final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_NFC);
+ }
+
+ @Before
+ public void setUp() {
+ assumeTrue(supportsHardware());
+ mNfcAdapter = NfcAdapter.getDefaultAdapter(InstrumentationRegistry.getTargetContext());
+ }
+
+ /**
+ * Verifies that isControllerAlwaysOnSupported() requires Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#NFC_SET_CONTROLLER_ALWAYS_ON}.
+ */
+ @Test
+ @AppModeFull
+ public void testIsControllerAlwaysOnSupported() {
+ try {
+ mNfcAdapter.isControllerAlwaysOnSupported();
+ fail("mNfcAdapter.isControllerAlwaysOnSupported() did not throw SecurityException"
+ + " as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that isControllerAlwaysOn() requires Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#NFC_SET_CONTROLLER_ALWAYS_ON}.
+ */
+ @Test
+ @AppModeFull
+ public void testIsControllerAlwaysOn() {
+ try {
+ mNfcAdapter.isControllerAlwaysOn();
+ fail("mNfcAdapter.isControllerAlwaysOn() did not throw SecurityException"
+ + " as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that setControllerAlwaysOn(true) requires Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#NFC_SET_CONTROLLER_ALWAYS_ON}.
+ */
+ @Test
+ @AppModeFull
+ public void testSetControllerAlwaysOnTrue() {
+ try {
+ mNfcAdapter.setControllerAlwaysOn(true);
+ fail("mNfcAdapter.setControllerAlwaysOn(true) did not throw SecurityException"
+ + " as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that setControllerAlwaysOn(false) requires Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#NFC_SET_CONTROLLER_ALWAYS_ON}.
+ */
+ @Test
+ @AppModeFull
+ public void testSetControllerAlwaysOnFalse() {
+ try {
+ mNfcAdapter.setControllerAlwaysOn(false);
+ fail("mNfcAdapter.setControllerAlwaysOn(true) did not throw SecurityException"
+ + " as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that registerControllerAlwaysOnListener() requires Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#NFC_SET_CONTROLLER_ALWAYS_ON}.
+ */
+ @Test
+ @AppModeFull
+ public void testRegisterControllerAlwaysOnListener() {
+ try {
+ mNfcAdapter.registerControllerAlwaysOnListener(
+ new SynchronousExecutor(), new AlwaysOnStateListener());
+ fail("mNfcAdapter.registerControllerAlwaysOnListener did not throw"
+ + "SecurityException as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ /**
+ * Verifies that unregisterControllerAlwaysOnListener() requires Permission.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#NFC_SET_CONTROLLER_ALWAYS_ON}.
+ */
+ @Test
+ @AppModeFull
+ public void testUnregisterControllerAlwaysOnListener() {
+ try {
+ mNfcAdapter.unregisterControllerAlwaysOnListener(new AlwaysOnStateListener());
+ fail("mNfcAdapter.unregisterControllerAlwaysOnListener did not throw"
+ + "SecurityException as expected");
+ } catch (SecurityException se) {
+ // Expected Exception
+ }
+ }
+
+ private class SynchronousExecutor implements Executor {
+ public void execute(Runnable r) {
+ r.run();
+ }
+ }
+
+ private class AlwaysOnStateListener implements ControllerAlwaysOnListener {
+ @Override
+ public void onControllerAlwaysOnChanged(boolean isEnabled) {
+ // Do nothing
+ }
+ }
+}
diff --git a/tests/tests/permission/src/android/permission/cts/SplitPermissionTest.java b/tests/tests/permission/src/android/permission/cts/SplitPermissionTest.java
index b837976..1c834cece 100644
--- a/tests/tests/permission/src/android/permission/cts/SplitPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/SplitPermissionTest.java
@@ -270,22 +270,6 @@
* If a permission was granted before the split happens, the new permission should inherit the
* granted state.
*
- * This is a duplicate of {@link #inheritGrantedPermissionState} but for the storage permission
- */
- @Test
- public void inheritGrantedPermissionStateStorage() throws Exception {
- install(APK_STORAGE_29);
- grantPermission(APP_PKG, READ_EXTERNAL_STORAGE);
-
- install(APK_STORAGE_28);
-
- assertPermissionGranted(ACCESS_MEDIA_LOCATION);
- }
-
- /**
- * If a permission was granted before the split happens, the new permission should inherit the
- * granted state.
- *
* <p>App using a shared uid
*/
@Test
diff --git a/tests/tests/permission2/res/raw/OWNERS b/tests/tests/permission2/res/raw/OWNERS
index a67ff98..04895ff 100644
--- a/tests/tests/permission2/res/raw/OWNERS
+++ b/tests/tests/permission2/res/raw/OWNERS
@@ -2,6 +2,7 @@
cbrubaker@google.com
hackbod@google.com
toddke@google.com
+patb@google.com
yamasani@google.com
michaelwr@google.com
narayan@google.com
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index a887a26..8695968 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -325,7 +325,7 @@
<protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_SEND_MULTIPLE" />
<protected-broadcast android:name="com.android.nfc.handover.action.CANCEL_HANDOVER_TRANSFER" />
- <protected-broadcast android:name="android.intent.action.CLEAR_DNS_CACHE" />
+ <protected-broadcast android:name="android.net.action.CLEAR_DNS_CACHE" />
<protected-broadcast android:name="android.intent.action.PROXY_CHANGE" />
<protected-broadcast android:name="android.os.UpdateLock.UPDATE_LOCK_CHANGED" />
@@ -559,8 +559,6 @@
<protected-broadcast android:name="android.intent.action.DYNAMIC_SENSOR_CHANGED" />
- <protected-broadcast android:name="android.intent.action.ACTION_RADIO_OFF" />
-
<protected-broadcast android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
<protected-broadcast android:name="android.accounts.action.ACCOUNT_REMOVED" />
<protected-broadcast android:name="android.accounts.action.VISIBLE_ACCOUNTS_CHANGED" />
@@ -1862,6 +1860,12 @@
android:label="@string/permlab_preferredPaymentInfo"
android:protectionLevel="normal" />
+ <!-- @SystemApi Allows access to set NFC controller always on states.
+ <p>Protection level: signature|privileged
+ @hide -->
+ <permission android:name="android.permission.NFC_SET_CONTROLLER_ALWAYS_ON"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi Allows an internal user to use privileged SecureElement APIs.
@hide -->
<permission android:name="android.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION"
@@ -2517,10 +2521,6 @@
<permission android:name="android.permission.CREATE_USERS"
android:protectionLevel="signature" />
- <!-- @TestApi @hide Allows an application to query user info for all users on the device. -->
- <permission android:name="android.permission.QUERY_USERS"
- android:protectionLevel="signature" />
-
<!-- @hide Allows an application to set the profile owners and the device owner.
This permission is not available to third party applications.-->
<permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"
@@ -2528,6 +2528,16 @@
android:label="@string/permlab_manageProfileAndDeviceOwners"
android:description="@string/permdesc_manageProfileAndDeviceOwners" />
+ <!-- @TestApi @hide Allows an application to reset the record of previous system update freeze
+ periods. -->
+ <permission android:name="android.permission.CLEAR_FREEZE_PERIOD"
+ android:protectionLevel="signature" />
+
+ <!-- @TestApi @hide Allows an application to force available DevicePolicyManager logs to
+ DPC. -->
+ <permission android:name="android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to get full detailed information about
recently running tasks, with full fidelity to the real state.
@hide -->
@@ -3742,6 +3752,13 @@
<permission android:name="com.android.permission.INSTALL_EXISTING_PACKAGES"
android:protectionLevel="signature|privileged" />
+ <!-- @TestApi Allows a testOnly application to get installed.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.INSTALL_TEST_ONLY_PACKAGE"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi @TestApi Allows an application to clear user data.
<p>Not for use by third-party applications
@hide
@@ -4062,6 +4079,11 @@
<permission android:name="android.permission.MODIFY_AUDIO_ROUTING"
android:protectionLevel="signature|privileged" />
+ <!-- @TestApi Allows an application to query audio related state.
+ @hide -->
+ <permission android:name="android.permission.QUERY_AUDIO_STATE"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to modify what effects are applied to all audio
(matching certain criteria) from any application.
<p>Not for use by third-party applications.</p>
@@ -4536,6 +4558,11 @@
<permission android:name="android.permission.SET_INITIAL_LOCK"
android:protectionLevel="signature|setup"/>
+ <!-- @TestApi Allows applications to set and verify lockscreen credentials.
+ @hide -->
+ <permission android:name="android.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS"
+ android:protectionLevel="signature"/>
+
<!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide -->
<permission android:name="android.permission.MANAGE_FINGERPRINT"
android:protectionLevel="signature|privileged" />
@@ -5081,9 +5108,16 @@
<permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"
android:protectionLevel="signature|privileged" />
<!-- Allows an app to override compat change config.
+ This permission only allows to override config on debuggable builds or test-apks and is
+ therefore a less powerful version of OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD.
@hide <p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an app to override compat change config on release builds.
+ Only ChangeIds that are annotated as @Overridable can be overridden on release builds.
+ @hide -->
+ <permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"
+ android:protectionLevel="signature|privileged" />
<!-- Allows input events to be monitored. Very dangerous! @hide -->
<permission android:name="android.permission.MONITOR_INPUT"
@@ -5129,6 +5163,10 @@
<permission android:name="android.permission.INPUT_CONSUMER"
android:protectionLevel="signature" />
+ <!-- @hide @SystemApi Allows the holder to manage app hibernation states for packages -->
+ <permission android:name="android.permission.MANAGE_APP_HIBERNATION"
+ android:protectionLevel="signature|installer" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
diff --git a/tests/tests/permission3/res/values-watch/strings.xml b/tests/tests/permission3/res/values-watch/strings.xml
new file mode 100755
index 0000000..5a7c933
--- /dev/null
+++ b/tests/tests/permission3/res/values-watch/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <string name="deny">Deny anyway</string>
+</resources>
diff --git a/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java b/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
index e842917..9a23af5 100644
--- a/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
+++ b/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
@@ -87,6 +87,8 @@
PackageManager.MATCH_DEFAULT_ONLY).activityInfo.packageName;
assumeFalse("Skipping test: Auto does not support provider android.settings.panel", isCar());
+ assumeFalse(
+ "Skipping test: Watch does not support provider android.settings.panel", isWatch());
}
@After
@@ -315,4 +317,8 @@
PackageManager pm = mContext.getPackageManager();
return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
}
+
+ private boolean isWatch() {
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+ }
}
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java
index 11a0e66..2416fd3 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java
@@ -118,10 +118,8 @@
Log.d(TAG, "Using volume " + mVolumeName);
mExternalImages = MediaStore.Images.Media.getContentUri(mVolumeName);
- final Resources res = mContext.getResources();
- final Configuration config = res.getConfiguration();
- mLargestDimension = (int) (Math.max(config.screenWidthDp, config.screenHeightDp)
- * res.getDisplayMetrics().density);
+ final DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
+ mLargestDimension = Math.max(metrics.widthPixels, metrics.heightPixels);
}
private void prepareImages() throws Exception {
diff --git a/tests/tests/renderscript/Android.mk b/tests/tests/renderscript/Android.mk
index bf121c2..20fe73e 100644
--- a/tests/tests/renderscript/Android.mk
+++ b/tests/tests/renderscript/Android.mk
@@ -18,6 +18,8 @@
# Replace "Example" with your name.
LOCAL_PACKAGE_NAME := CtsRenderscriptTestCases
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
# Don't include this package in any target.
LOCAL_MODULE_TAGS := optional
diff --git a/tests/tests/renderscriptlegacy/Android.bp b/tests/tests/renderscriptlegacy/Android.bp
new file mode 100644
index 0000000..4f20661
--- /dev/null
+++ b/tests/tests/renderscriptlegacy/Android.bp
@@ -0,0 +1,31 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsRenderscriptLegacyTestCases",
+ defaults: ["cts_defaults"],
+ static_libs: ["ctstestrunner-axt"],
+ srcs: ["src/**/*.java"],
+ sdk_version: "19",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+}
diff --git a/tests/tests/renderscriptlegacy/Android.mk b/tests/tests/renderscriptlegacy/Android.mk
deleted file mode 100644
index 98df8e9..0000000
--- a/tests/tests/renderscriptlegacy/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsRenderscriptLegacyTestCases
-
-# Don't include this package in any target.
-LOCAL_MODULE_TAGS := optional
-
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner-axt
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := 19
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-
-include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/resourcesloader/OWNERS b/tests/tests/resourcesloader/OWNERS
index d2cb9ad..57228c7 100644
--- a/tests/tests/resourcesloader/OWNERS
+++ b/tests/tests/resourcesloader/OWNERS
@@ -1,4 +1,5 @@
# Bug component: 568761
rtmitchell@google.com
chiuwinson@google.com
-toddke@google.com
\ No newline at end of file
+toddke@google.com
+patb@google.com
diff --git a/tests/tests/resourcesloader/src/android/content/res/loader/cts/ResourcesLoaderTestBase.kt b/tests/tests/resourcesloader/src/android/content/res/loader/cts/ResourcesLoaderTestBase.kt
index 1295fe1..84ed5a7c 100644
--- a/tests/tests/resourcesloader/src/android/content/res/loader/cts/ResourcesLoaderTestBase.kt
+++ b/tests/tests/resourcesloader/src/android/content/res/loader/cts/ResourcesLoaderTestBase.kt
@@ -46,7 +46,7 @@
companion object {
/** Converts the map to a stable JSON string representation. */
fun mapToString(m: Map<String, String>): String {
- return JSONObject(ArrayMap<String, String>().apply { putAll(m) }).toString()
+ return JSONObject(ArrayMap<Any?, Any?>().apply { putAll(m) }).toString()
}
/** Creates a lambda that runs multiple resources queries and concatenates the results. */
diff --git a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
index 00ddc34..39cc25b 100644
--- a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
+++ b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
@@ -316,14 +316,6 @@
}
@Test
- public void requestEmptyRoleThenDeniedAutomatically() throws Exception {
- requestRole("");
- Pair<Integer, Intent> result = waitForResult();
-
- assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED);
- }
-
- @Test
public void requestInvalidRoleThenDeniedAutomatically() throws Exception {
requestRole("invalid");
Pair<Integer, Intent> result = waitForResult();
@@ -378,7 +370,7 @@
@Nullable
private UiObject2 findDontAskAgainCheck(boolean expected) throws UiObjectNotFoundException {
- BySelector selector = By.text("Don\u2019t ask again");
+ BySelector selector = By.res("com.android.permissioncontroller:id/dont_ask_again");
return expected
? waitFindObject(selector)
: waitFindObjectOrNull(selector, UNEXPECTED_TIMEOUT_MILLIS);
diff --git a/tests/tests/rsblas/Android.mk b/tests/tests/rsblas/Android.mk
index 6b18c5d..ffe4944 100644
--- a/tests/tests/rsblas/Android.mk
+++ b/tests/tests/rsblas/Android.mk
@@ -17,6 +17,8 @@
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := CtsRsBlasTestCases
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
# Don't include this package in any target.
LOCAL_MODULE_TAGS := optional
diff --git a/tests/tests/rscpp/Android.mk b/tests/tests/rscpp/Android.mk
index 79e8a2c..8231e41 100644
--- a/tests/tests/rscpp/Android.mk
+++ b/tests/tests/rscpp/Android.mk
@@ -18,6 +18,8 @@
# Replace "Example" with your name.
LOCAL_PACKAGE_NAME := CtsRsCppTestCases
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
# Don't include this package in any target.
LOCAL_MODULE_TAGS := optional
diff --git a/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp b/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp
index ad089a2..0cc60e8 100644
--- a/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp
+++ b/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp
@@ -57,6 +57,12 @@
continue;
}
+ if (android::base::EqualsIgnoreCase(entry.fs_type, "emmc")) {
+ GTEST_LOG_(INFO) << entry.mount_point << " has emmc fs_type, skipping"
+ << " hashtree algorithm verification";
+ continue;
+ }
+
GTEST_LOG_(ERROR) << "partition enabled verity " << entry.mount_point;
// The verity sysprop use "system" as the partition name in the system as
diff --git a/tests/tests/selinux/common/src/android/security/SELinuxTargetSdkTestBase.java b/tests/tests/selinux/common/src/android/security/SELinuxTargetSdkTestBase.java
index 496270f..799b755 100644
--- a/tests/tests/selinux/common/src/android/security/SELinuxTargetSdkTestBase.java
+++ b/tests/tests/selinux/common/src/android/security/SELinuxTargetSdkTestBase.java
@@ -62,21 +62,13 @@
}
}
- protected static void checkNetlinkRouteGetlink(boolean expectAllowed) throws IOException {
- if (!expectAllowed) {
- assertEquals(
- "RTM_GETLINK is not allowed on a netlink route sockets. Verify that the"
- + " following patch has been applied to your kernel: "
- + "https://android-review.googlesource.com/q/I7b44ce60ad98f858c412722d41b9842f8577151f",
- 13,
- checkNetlinkRouteGetlink());
- } else {
- assertEquals(
- "RTM_GETLINK should be allowed netlink route sockets for apps with "
- + "targetSdkVersion <= Q",
- -1,
- checkNetlinkRouteGetlink());
- }
+ protected static void noNetlinkRouteGetlink() throws IOException {
+ assertEquals(
+ "RTM_GETLINK is not allowed on netlink route sockets. Verify that the"
+ + " following patch has been applied to your kernel: "
+ + "https://android-review.googlesource.com/q/I7b44ce60ad98f858c412722d41b9842f8577151f",
+ 13,
+ checkNetlinkRouteGetlink());
}
protected static void noNetlinkRouteBind() throws IOException {
@@ -164,10 +156,18 @@
}
/**
+ * Verify that apps are not able to see MAC addresses of ethernet devices.
+ */
+ protected static void checkNetworkInterfaceHardwareAddress_returnsNull() throws Exception {
+ assertNotNull(NetworkInterface.getNetworkInterfaces());
+ for (NetworkInterface nif : Collections.list(NetworkInterface.getNetworkInterfaces())) {
+ assertNull(nif.getHardwareAddress());
+ }
+ }
+
+ /**
* Verify that apps having targetSdkVersion <= 29 get an anonymized MAC
* address (02:00:00:00:00:00) instead of a null MAC for ethernet interfaces.
- * The counterpart of this test (testing for targetSdkVersion > 29) is
- * {@link libcore.java.net.NetworkInterfaceTest#testGetHardwareAddress_returnsNull()}.
*/
protected static void checkNetworkInterface_returnsAnonymizedHardwareAddresses()
throws Exception {
diff --git a/tests/tests/selinux/selinuxEphemeral/src/android/security/SELinuxTargetSdkTest.java b/tests/tests/selinux/selinuxEphemeral/src/android/security/SELinuxTargetSdkTest.java
index 1098a6f..d642e45 100644
--- a/tests/tests/selinux/selinuxEphemeral/src/android/security/SELinuxTargetSdkTest.java
+++ b/tests/tests/selinux/selinuxEphemeral/src/android/security/SELinuxTargetSdkTest.java
@@ -79,10 +79,14 @@
}
public void testNoNetlinkRouteGetlink() throws IOException {
- checkNetlinkRouteGetlink(false);
+ noNetlinkRouteGetlink();
}
public void testNoNetlinkRouteBind() throws IOException {
noNetlinkRouteBind();
}
+
+ public void testNetworkInterface() throws Exception {
+ checkNetworkInterfaceHardwareAddress_returnsNull();
+ }
}
diff --git a/tests/tests/selinux/selinuxTargetSdk27/src/android/security/SELinuxTargetSdkTest.java b/tests/tests/selinux/selinuxTargetSdk27/src/android/security/SELinuxTargetSdkTest.java
index 5e2f75d..e3f2cf6 100644
--- a/tests/tests/selinux/selinuxTargetSdk27/src/android/security/SELinuxTargetSdkTest.java
+++ b/tests/tests/selinux/selinuxTargetSdk27/src/android/security/SELinuxTargetSdkTest.java
@@ -68,4 +68,12 @@
public void testNetworkInterface() throws Exception {
checkNetworkInterface_returnsAnonymizedHardwareAddresses();
}
+
+ public void testNoNetlinkRouteGetlink() throws IOException {
+ noNetlinkRouteGetlink();
+ }
+
+ public void testNoNetlinkRouteBind() throws IOException {
+ noNetlinkRouteBind();
+ }
}
diff --git a/tests/tests/selinux/selinuxTargetSdk28/src/android/security/SELinuxTargetSdkTest.java b/tests/tests/selinux/selinuxTargetSdk28/src/android/security/SELinuxTargetSdkTest.java
index 29b68db..8f2aea5 100644
--- a/tests/tests/selinux/selinuxTargetSdk28/src/android/security/SELinuxTargetSdkTest.java
+++ b/tests/tests/selinux/selinuxTargetSdk28/src/android/security/SELinuxTargetSdkTest.java
@@ -68,4 +68,12 @@
public void testNetworkInterface() throws Exception {
checkNetworkInterface_returnsAnonymizedHardwareAddresses();
}
+
+ public void testNoNetlinkRouteGetlink() throws IOException {
+ noNetlinkRouteGetlink();
+ }
+
+ public void testNoNetlinkRouteBind() throws IOException {
+ noNetlinkRouteBind();
+ }
}
diff --git a/tests/tests/selinux/selinuxTargetSdk29/src/android/security/SELinuxTargetSdkTest.java b/tests/tests/selinux/selinuxTargetSdk29/src/android/security/SELinuxTargetSdkTest.java
index c1d93dc..3429f58 100644
--- a/tests/tests/selinux/selinuxTargetSdk29/src/android/security/SELinuxTargetSdkTest.java
+++ b/tests/tests/selinux/selinuxTargetSdk29/src/android/security/SELinuxTargetSdkTest.java
@@ -42,9 +42,8 @@
checkDex2oatAccess(false);
}
}
-
- public void testNetlinkRouteGetlinkSucceeds() throws IOException {
- checkNetlinkRouteGetlink(true);
+ public void testNoNetlinkRouteGetlink() throws IOException {
+ noNetlinkRouteGetlink();
}
public void testNoNetlinkRouteBind() throws IOException {
diff --git a/tests/tests/selinux/selinuxTargetSdkCurrent/src/android/security/SELinuxTargetSdkTest.java b/tests/tests/selinux/selinuxTargetSdkCurrent/src/android/security/SELinuxTargetSdkTest.java
index 4de03b0..859864e 100644
--- a/tests/tests/selinux/selinuxTargetSdkCurrent/src/android/security/SELinuxTargetSdkTest.java
+++ b/tests/tests/selinux/selinuxTargetSdkCurrent/src/android/security/SELinuxTargetSdkTest.java
@@ -34,7 +34,7 @@
}
public void testNoNetlinkRouteGetlink() throws IOException {
- checkNetlinkRouteGetlink(false);
+ noNetlinkRouteGetlink();
}
public void testNoNetlinkRouteBind() throws IOException {
diff --git a/tests/tests/settings/src/android/settings/cts/WifiSliceTest.java b/tests/tests/settings/src/android/settings/cts/WifiSliceTest.java
index 26d78a5..78461ce 100644
--- a/tests/tests/settings/src/android/settings/cts/WifiSliceTest.java
+++ b/tests/tests/settings/src/android/settings/cts/WifiSliceTest.java
@@ -74,6 +74,8 @@
public void setUp() throws Exception {
assumeFalse("Skipping test: Auto does not support provider android.settings.slices", isCar());
assumeFalse("Skipping test: TV does not support provider android.settings.slices", isTv());
+ assumeFalse(
+ "Skipping test: Watch does not support provider android.settings.slices", isWatch());
mWifiSlice = mSliceManager.bindSlice(WIFI_SLICE_URI, Collections.emptySet());
mAssistant = Secure.getString(mContext.getContentResolver(), ASSISTANT);
}
@@ -170,6 +172,10 @@
&& pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
}
+ private boolean isWatch() {
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+ }
+
private boolean isWifiEnabled() {
final WifiManager wifiManager = mContext.getSystemService(WifiManager.class);
return wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED
diff --git a/tests/tests/shortcutmanager/OWNERS b/tests/tests/shortcutmanager/OWNERS
index 557370d..2f325bb 100644
--- a/tests/tests/shortcutmanager/OWNERS
+++ b/tests/tests/shortcutmanager/OWNERS
@@ -1,3 +1,5 @@
# Bug component: 166829
+sunnygoyal@google.com
+pinyaoting@google.com
omakoto@google.com
yamasani@google.com
diff --git a/tests/tests/simphonebookprovider/AndroidTest.xml b/tests/tests/simphonebookprovider/AndroidTest.xml
index 0d7df7a..e21c163 100644
--- a/tests/tests/simphonebookprovider/AndroidTest.xml
+++ b/tests/tests/simphonebookprovider/AndroidTest.xml
@@ -17,6 +17,7 @@
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="framework" />
+ <option name="config-descriptor:metadata" key="token" value="SIM_CARD" />
<!-- Instant apps can't access the system providers. -->
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
diff --git a/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/RemovableSims.java b/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/RemovableSims.java
index 1d32f3a..27a3389 100644
--- a/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/RemovableSims.java
+++ b/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/RemovableSims.java
@@ -74,7 +74,10 @@
Map<Integer, List<SubscriptionInfo>> subscriptionsByCardId = allSubscriptions.stream()
.collect(Collectors.groupingBy(SubscriptionInfo::getCardId));
for (UiccCardInfo cardInfo : uiccCards) {
- if (!cardInfo.isRemovable() || cardInfo.isEuicc()) {
+ // On GSI builds the eUICC won't be loaded but its card info will still be returned
+ // and so it will have UNINITIALIZED_CARD_ID permanently.
+ if (!cardInfo.isRemovable() || cardInfo.isEuicc() ||
+ cardInfo.getCardId() == TelephonyManager.UNINITIALIZED_CARD_ID) {
continue;
}
mRemovableSimSlotCount++;
diff --git a/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookContract_ContentNotificationsTest.java b/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookContract_ContentNotificationsTest.java
index 87648b1..bee9449 100644
--- a/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookContract_ContentNotificationsTest.java
+++ b/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookContract_ContentNotificationsTest.java
@@ -20,6 +20,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.hamcrest.Matchers.oneOf;
import static org.junit.Assume.assumeThat;
import static java.util.concurrent.TimeUnit.SECONDS;
@@ -38,7 +39,6 @@
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
-import android.util.Log;
import androidx.annotation.Nullable;
import androidx.test.core.app.ApplicationProvider;
@@ -186,11 +186,16 @@
Manifest.permission.MODIFY_PHONE_STATE, Manifest.permission.READ_PHONE_STATE);
int result = resultFuture.get(30, SECONDS);
- if (result != TelephonyManager.SET_SIM_POWER_STATE_ALREADY_IN_STATE &&
- result != TelephonyManager.SET_SIM_POWER_STATE_SUCCESS) {
- Log.w(TAG, "setSimPowerStateForSlot failed for slot=" + slotIndex + " result="
- + result);
- }
+ assumeThat("setSimPowerStateForSlot failed for slot=" + slotIndex,
+ result, oneOf(
+ TelephonyManager.SET_SIM_POWER_STATE_ALREADY_IN_STATE,
+ TelephonyManager.SET_SIM_POWER_STATE_SUCCESS));
+ int simState = SystemUtil.runWithShellPermissionIdentity(() ->
+ telephonyManager.getSimState(slotIndex),
+ Manifest.permission.READ_PHONE_STATE);
+ // This doesn't work on Cuttlefish so confirm the SIM was actually powered off.
+ assumeThat(simState, Matchers.not(oneOf(
+ TelephonyManager.SIM_STATE_PRESENT, TelephonyManager.SIM_STATE_READY)));
}
private static class RecordingContentObserver extends ContentObserver {
diff --git a/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookContract_SimRecordsNoSimTest.java b/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookContract_SimRecordsNoSimTest.java
index 55fdd41..4078816 100644
--- a/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookContract_SimRecordsNoSimTest.java
+++ b/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookContract_SimRecordsNoSimTest.java
@@ -24,6 +24,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assume.assumeThat;
+
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
@@ -33,6 +35,7 @@
import android.provider.SimPhonebookContract;
import android.provider.SimPhonebookContract.ElementaryFiles;
import android.provider.SimPhonebookContract.SimRecords;
+import android.telephony.TelephonyManager;
import androidx.annotation.NonNull;
import androidx.test.core.app.ApplicationProvider;
@@ -151,9 +154,14 @@
values.put(SimRecords.NAME, "Name");
values.put(SimRecords.PHONE_NUMBER, "8005550101");
- assertThrows(UnsupportedOperationException.class,
- () -> mResolver.insert(
- SimRecords.getContentUri(MISSING_SIM_SUBSCRIPTION_ID, EF_FDN), values));
+ // Depending on the context where the test is run the test app may have carrier privileges
+ // e.g. omitting this will cause a failure when running on cuttlefish if it is launched
+ // with --modem_simulator_sim_type=2
+ if (!mContext.getSystemService(TelephonyManager.class).hasCarrierPrivileges()) {
+ assertThrows(UnsupportedOperationException.class,
+ () -> mResolver.insert(
+ SimRecords.getContentUri(MISSING_SIM_SUBSCRIPTION_ID, EF_FDN), values));
+ }
assertThrows(UnsupportedOperationException.class,
() -> mResolver.insert(
SimRecords.getContentUri(MISSING_SIM_SUBSCRIPTION_ID, EF_SDN), values));
diff --git a/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookRequirementsRule.java b/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookRequirementsRule.java
index e53694b..a7773b5 100644
--- a/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookRequirementsRule.java
+++ b/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/SimPhonebookRequirementsRule.java
@@ -22,6 +22,7 @@
import static org.junit.Assume.assumeThat;
import android.content.Context;
+import android.telephony.TelephonyManager;
import androidx.test.core.app.ApplicationProvider;
@@ -42,6 +43,13 @@
@Override
protected void before() {
Context context = ApplicationProvider.getApplicationContext();
+ TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
+
+ // Skip the test if the device doesn't appear to have any multi-SIM capability. The checks
+ // that follow this one are a bit flaky on devices that have an eSIM but don't support
+ // DSDS or DSDA (e.g. crosshatch and blueline).
+ assumeThat("not enough SIMs",
+ telephonyManager.getSupportedModemCount(), greaterThanOrEqualTo(mMinimumSimCount));
RemovableSims removableSims = new RemovableSims(context);
assumeThat(removableSims.getRemovableSimSlotCount(),
diff --git a/tests/tests/simpleperf/Android.mk b/tests/tests/simpleperf/Android.mk
index 351ff22..23e9245 100644
--- a/tests/tests/simpleperf/Android.mk
+++ b/tests/tests/simpleperf/Android.mk
@@ -21,7 +21,7 @@
libsimpleperf_etm_decoder \
libbacktrace \
libunwindstack \
- libdexfile_external_static \
+ libdexfile_static \
libziparchive \
libz \
libgtest \
diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
index b2c2539..149b0a8 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
+import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.database.Cursor;
import android.media.AudioManager;
@@ -171,14 +172,19 @@
return;
}
- // Assume we start in normal mode at the start of all Telecom tests.
- // A failure to leave car mode in any of the tests would cause subsequent test failures,
- // but this failure should not affect other tests.
+ // Assume we start in normal mode at the start of all Telecom tests; a failure to leave car
+ // mode in any of the tests would cause subsequent test failures.
+ // For Watch, UI_MODE shouldn't be normal mode.
mUiModeManager = mContext.getSystemService(UiModeManager.class);
if (mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR) {
mUiModeManager.disableCarMode(0);
}
- assertUiMode(Configuration.UI_MODE_TYPE_NORMAL);
+
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ assertUiMode(Configuration.UI_MODE_TYPE_WATCH);
+ } else {
+ assertUiMode(Configuration.UI_MODE_TYPE_NORMAL);
+ }
mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
diff --git a/tests/tests/telecom/src/android/telecom/cts/BluetoothCallQualityReportTest.java b/tests/tests/telecom/src/android/telecom/cts/BluetoothCallQualityReportTest.java
new file mode 100644
index 0000000..dc40407
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/BluetoothCallQualityReportTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.telecom.cts;
+
+import android.telecom.BluetoothCallQualityReport;
+
+public class BluetoothCallQualityReportTest extends BaseTelecomTestWithMockServices {
+ /**
+ * Test passing of BT call quality report to CDS.
+ */
+ public void testBluetoothCallQualityReport() {
+ long timestamp = System.currentTimeMillis();
+ int rssi = 1;
+ int snr = 2;
+ int retransmissionCount = 3;
+ int packetsNotReceiveCount = 4;
+ int negativeAcknowledgementCount = 5;
+
+ BluetoothCallQualityReport report = new BluetoothCallQualityReport.Builder()
+ .setSentTimestampMillis(timestamp)
+ .setChoppyVoice(true)
+ .setRssiDbm(rssi)
+ .setSnrDb(snr)
+ .setRetransmittedPacketsCount(retransmissionCount)
+ .setPacketsNotReceivedCount(packetsNotReceiveCount)
+ .setNegativeAcknowledgementCount(negativeAcknowledgementCount)
+ .build();
+
+ assertEquals(timestamp, report.getSentTimestampMillis());
+ assertEquals(true, report.isChoppyVoice());
+ assertEquals(rssi, report.getRssiDbm());
+ assertEquals(snr, report.getSnrDb());
+ assertEquals(retransmissionCount, report.getRetransmittedPacketsCount());
+ assertEquals(packetsNotReceiveCount, report.getPacketsNotReceivedCount());
+ assertEquals(negativeAcknowledgementCount, report.getNegativeAcknowledgementCount());
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/telecom/src/android/telecom/cts/CarModeInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/CarModeInCallServiceTest.java
index 0e51b37..c7fe892 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CarModeInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CarModeInCallServiceTest.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.res.Configuration;
+import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
@@ -48,6 +49,10 @@
return;
}
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ return;
+ }
+
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.adoptShellPermissionIdentity("android.permission.ENTER_CAR_MODE_PRIORITIZED",
"android.permission.CONTROL_INCALL_EXPERIENCE");
@@ -69,6 +74,10 @@
return;
}
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ return;
+ }
+
if (mCarModeIncallServiceControlOne != null) {
mCarModeIncallServiceControlOne.reset();
}
@@ -91,6 +100,10 @@
return;
}
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ return;
+ }
+
enableAndVerifyCarMode(mCarModeIncallServiceControlOne, 1000);
disableAndVerifyCarMode(mCarModeIncallServiceControlOne, Configuration.UI_MODE_TYPE_NORMAL);
}
@@ -104,6 +117,10 @@
return;
}
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ return;
+ }
+
enableAndVerifyCarMode(mCarModeIncallServiceControlOne, 1000);
// Place a call and verify we bound to the Car Mode InCallService
@@ -126,6 +143,10 @@
return;
}
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ return;
+ }
+
enableAndVerifyCarMode(mCarModeIncallServiceControlOne, 1000);
enableAndVerifyCarMode(mCarModeIncallServiceControlTwo, 999);
@@ -152,6 +173,10 @@
return;
}
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ return;
+ }
+
// Place a call and verify it went to the default dialer
placeAndVerifyCall();
verifyConnectionForOutgoingCall();
@@ -173,6 +198,10 @@
return;
}
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ return;
+ }
+
// Place a call and verify it went to the default dialer
placeAndVerifyCall();
verifyConnectionForOutgoingCall();
@@ -209,6 +238,10 @@
return;
}
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ return;
+ }
+
// Place a call and verify it went to the default dialer
placeAndVerifyCall();
verifyConnectionForOutgoingCall();
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
index 89eb5a6..68ad014 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertTrue;
import android.content.Intent;
+import android.os.IBinder;
import android.telecom.Conference;
import android.telecom.Connection;
import android.telecom.ConnectionRequest;
@@ -58,8 +59,8 @@
private static boolean sIsBound = false;
private static CountDownLatch sServiceUnBoundLatch = new CountDownLatch(1);
- public CtsConnectionService() throws Exception {
- super();
+ @Override
+ public void onBindClient(Intent intent) {
sTelecomConnectionService = this;
sIsBound = true;
}
@@ -77,7 +78,6 @@
public static void tearDown() {
synchronized(sLock) {
- sTelecomConnectionService = null;
sConnectionService = null;
}
}
@@ -185,14 +185,24 @@
public static void addConferenceToTelecom(Conference conference) {
synchronized(sLock) {
- sTelecomConnectionService.addConference(conference);
+ if (sTelecomConnectionService != null) {
+ sTelecomConnectionService.addConference(conference);
+ } else {
+ Log.e(LOG_TAG, "addConferenceToTelecom called when"
+ + " sTelecomConnectionService null!");
+ }
}
}
public static void addExistingConnectionToTelecom(
PhoneAccountHandle phoneAccountHandle, Connection connection) {
synchronized(sLock) {
- sTelecomConnectionService.addExistingConnection(phoneAccountHandle, connection);
+ if (sTelecomConnectionService != null) {
+ sTelecomConnectionService.addExistingConnection(phoneAccountHandle, connection);
+ } else {
+ Log.e(LOG_TAG, "addExistingConnectionToTelecom called when"
+ + " sTelecomConnectionService null!");
+ }
}
}
@@ -209,8 +219,14 @@
PhoneAccountHandle connectionManagerPhoneAccount,
ConnectionRequest request) {
synchronized(sLock) {
- return sTelecomConnectionService.createRemoteOutgoingConnection(
- connectionManagerPhoneAccount, request);
+ if (sTelecomConnectionService != null) {
+ return sTelecomConnectionService.createRemoteOutgoingConnection(
+ connectionManagerPhoneAccount, request);
+ } else {
+ Log.e(LOG_TAG, "createRemoteOutgoingConnectionToTelecom called when"
+ + " sTelecomConnectionService null!");
+ return null;
+ }
}
}
@@ -218,8 +234,14 @@
PhoneAccountHandle connectionManagerPhoneAccount,
ConnectionRequest request) {
synchronized(sLock) {
- return sTelecomConnectionService.createRemoteIncomingConnection(
- connectionManagerPhoneAccount, request);
+ if (sTelecomConnectionService != null) {
+ return sTelecomConnectionService.createRemoteIncomingConnection(
+ connectionManagerPhoneAccount, request);
+ } else {
+ Log.e(LOG_TAG, "createRemoteIncomingConnectionToTelecom called when"
+ + " sTelecomConnectionService null!");
+ return null;
+ }
}
}
@@ -227,8 +249,14 @@
PhoneAccountHandle connectionManagerPhoneAccount,
ConnectionRequest request) {
synchronized (sLock) {
- return sTelecomConnectionService.createRemoteIncomingConference(
- connectionManagerPhoneAccount, request);
+ if (sTelecomConnectionService != null) {
+ return sTelecomConnectionService.createRemoteIncomingConference(
+ connectionManagerPhoneAccount, request);
+ } else {
+ Log.e(LOG_TAG, "createRemoteIncomingConferenceToTelecom called when"
+ + " sTelecomConnectionService null!");
+ return null;
+ }
}
}
@@ -237,8 +265,14 @@
PhoneAccountHandle connectionManagerPhoneAccount,
ConnectionRequest request) {
synchronized (sLock) {
- return sTelecomConnectionService.createRemoteOutgoingConference(
- connectionManagerPhoneAccount, request);
+ if (sTelecomConnectionService != null) {
+ return sTelecomConnectionService.createRemoteOutgoingConference(
+ connectionManagerPhoneAccount, request);
+ } else {
+ Log.e(LOG_TAG, "createRemoteOutgoingConferenceToTelecom called when"
+ + " sTelecomConnectionService null!");
+ return null;
+ }
}
}
@@ -275,6 +309,7 @@
sServiceUnBoundLatch.countDown();
sIsBound = false;
sConnectionService = null;
+ sTelecomConnectionService = null;
return super.onUnbind(intent);
}
diff --git a/tests/tests/telephony/current/Android.bp b/tests/tests/telephony/current/Android.bp
index 1876bc7..014d0a4 100644
--- a/tests/tests/telephony/current/Android.bp
+++ b/tests/tests/telephony/current/Android.bp
@@ -30,7 +30,9 @@
"src/android/telephony/ims/cts/TestSipDelegate.java",
"src/android/telephony/ims/cts/TestSipDelegateConnection.java",
"src/android/telephony/ims/cts/ImsUtils.java",
- "src/android/telephony/ims/cts/TestAcsClient.java",
+ "src/android/telephony/ims/cts/SipDialogAttributes.java",
+ "src/android/telephony/ims/cts/SipMessageUtils.java",
+ "src/android/telephony/ims/cts/TestAcsClient.java",
],
path: "src/",
}
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 0cf33b1..bf13b0c 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java
@@ -573,7 +573,7 @@
assertTrue("getPci() out of range [0, 1007], pci = " + pci, 0 <= pci && pci <= 1007);
int tac = nr.getTac();
- assertTrue("getTac() out of range [0, 65536], tac = " + tac, 0 <= tac && tac <= 65536);
+ assertTrue("getTac() out of range [0, 16777215], tac = " + tac, 0 <= tac && tac <= 16777215);
int nrArfcn = nr.getNrarfcn();
assertTrue("getNrarfcn() out of range [0, 3279165], nrarfcn = " + nrArfcn,
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/LteVopsSupportInfoTest.java b/tests/tests/telephony/current/src/android/telephony/cts/LteVopsSupportInfoTest.java
deleted file mode 100644
index 1832fad..0000000
--- a/tests/tests/telephony/current/src/android/telephony/cts/LteVopsSupportInfoTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.telephony.cts;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.os.Parcel;
-import android.telephony.LteVopsSupportInfo;
-
-import org.junit.Test;
-
-public class LteVopsSupportInfoTest {
-
- @Test
- public void testLteVopsSupportInfo() {
- LteVopsSupportInfo lteVops =
- new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_SUPPORTED,
- LteVopsSupportInfo.LTE_STATUS_SUPPORTED);
- assertEquals(0, lteVops.describeContents());
- assertEquals(LteVopsSupportInfo.LTE_STATUS_SUPPORTED, lteVops.getVopsSupport());
- assertEquals(LteVopsSupportInfo.LTE_STATUS_SUPPORTED, lteVops.getEmcBearerSupport());
-
- Parcel lteVopsParcel = Parcel.obtain();
- lteVops.writeToParcel(lteVopsParcel, 0);
- lteVopsParcel.setDataPosition(0);
- LteVopsSupportInfo checkLteVops =
- LteVopsSupportInfo.CREATOR.createFromParcel(lteVopsParcel);
- assertTrue(lteVops.equals(checkLteVops));
- }
-}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MmsTest.java b/tests/tests/telephony/current/src/android/telephony/cts/MmsTest.java
index 60b0de2..f10b27c 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/MmsTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/MmsTest.java
@@ -148,15 +148,12 @@
synchronized(mLock) {
final long startTime = SystemClock.elapsedRealtime();
long waitTime = timeout;
- while (waitTime > 0) {
+ while (!mDone && waitTime > 0) {
try {
mLock.wait(waitTime);
} catch (InterruptedException e) {
// Ignore
}
- if (mDone) {
- break;
- }
waitTime = timeout - (SystemClock.elapsedRealtime() - startTime);
}
Log.i(TAG, "Wait for sent: done=" + mDone + ", success=" + mSuccess);
@@ -183,15 +180,6 @@
}
Log.i(TAG, "testSendMmsMessage");
- // Prime the MmsService so that MMS config is loaded
- final SmsManager smsManager = SmsManager.getDefault();
- smsManager.getCarrierConfigValues();
- // MMS config is loaded asynchronously. Wait a bit so it will be loaded.
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- // Ignore
- }
final Context context = getContext();
// Register sent receiver
@@ -213,7 +201,7 @@
// Send
final PendingIntent pendingIntent = PendingIntent.getBroadcast(
context, 0, new Intent(ACTION_MMS_SENT), 0);
- smsManager.sendMultimediaMessage(context,
+ SmsManager.getDefault().sendMultimediaMessage(context,
contentUri, null/*locationUrl*/, null/*configOverrides*/, pendingIntent);
assertTrue(mSentReceiver.waitForSuccess(SENT_TIMEOUT));
sendFile.delete();
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/PhysicalChannelConfigTest.java b/tests/tests/telephony/current/src/android/telephony/cts/PhysicalChannelConfigTest.java
index cc534f7..eaa6b7d 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/PhysicalChannelConfigTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/PhysicalChannelConfigTest.java
@@ -36,6 +36,8 @@
private static final int CONNECTION_STATUS = PhysicalChannelConfig.CONNECTION_PRIMARY_SERVING;
private static final int CELL_BANDWIDTH = 12345;
private static final int CHANNEL_NUMBER = 1234;
+ private static final int DOWNLINK_FREQUENCY = 11100;
+ private static final int UPLINK_FREQUENCY = 11100;
private static final int FREQUENCY_RANGE = 1;
private static final int PHYSICAL_CELL_ID = 502;
private static final int PHYSICAL_INVALID_CELL_ID = 1008;
@@ -168,4 +170,32 @@
assertThat(mPhysicalChannelConfig.getFrequencyRange()).isEqualTo(
ServiceState.FREQUENCY_RANGE_LOW);
}
+
+ private void setupNrPhysicalChannelConfig() {
+ mPhysicalChannelConfig = new PhysicalChannelConfig.Builder()
+ .setPhysicalCellId(PHYSICAL_CELL_ID)
+ .setNetworkType(NETWORK_TYPE_NR)
+ .setCellConnectionStatus(CONNECTION_STATUS)
+ .setCellBandwidthDownlinkKhz(CELL_BANDWIDTH)
+ .setCellBandwidthUplinkKhz(CELL_BANDWIDTH)
+ .setContextIds(CONTEXT_IDS)
+ .setDownlinkChannelNumber(2220)
+ .setUplinkChannelNumber(2220)
+ .setBand(BAND)
+ .build();
+ }
+
+ @Test
+ public void testUplinkFrequencyKhz() {
+ setupNrPhysicalChannelConfig();
+
+ assertEquals(UPLINK_FREQUENCY, mPhysicalChannelConfig.getUplinkFrequencyKhz());
+ }
+
+ @Test
+ public void testDownlinkFrequencyKhz() {
+ setupNrPhysicalChannelConfig();
+
+ assertEquals(DOWNLINK_FREQUENCY, mPhysicalChannelConfig.getDownlinkFrequencyKhz());
+ }
}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/ServiceStateTest.java b/tests/tests/telephony/current/src/android/telephony/cts/ServiceStateTest.java
index 3ec048b..60b9106 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/ServiceStateTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/ServiceStateTest.java
@@ -29,7 +29,10 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import android.content.Context;
+import android.os.Build;
import android.os.Parcel;
import android.telephony.AccessNetworkConstants;
import android.telephony.LteVopsSupportInfo;
@@ -37,10 +40,14 @@
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
+import androidx.test.InstrumentationRegistry;
+
import org.junit.Before;
import org.junit.Test;
import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
public class ServiceStateTest {
private static final String OPERATOR_ALPHA_LONG = "CtsOperatorLong";
@@ -150,12 +157,38 @@
assertEquals(DUPLEX_MODE_TDD, serviceState.getDuplexMode());
}
+ private static Context getContext() {
+ return InstrumentationRegistry.getContext();
+ }
+
@Test
public void testToString() {
assertNotNull(serviceState.toString());
}
@Test
+ public void testNrStateRedacted() {
+ final TelephonyManager tm = getContext().getSystemService(TelephonyManager.class);
+
+ // Verify that NR State is not leaked in user builds.
+ if (!Build.IS_DEBUGGABLE) {
+ final String sss = tm.getServiceState().toString();
+ // The string leaked in previous releases is "nrState=<val>"; test that there is
+ // no matching or highly similar string leak, such as:
+ // nrState=NONE
+ // nrState=0
+ // mNrState=RESTRICTED
+ // NRSTATE=NOT_RESTRICTED
+ // nrState = CONNECTED
+ // etc.
+ Pattern p = Pattern.compile("nrState\\s*=\\s*[a-zA-Z0-9_]+", Pattern.CASE_INSENSITIVE);
+ Matcher m = p.matcher(sss);
+ // Need to use if (find) fail to ensure that the start and end are populated
+ if (m.find()) fail("Found nrState reported as: " + sss.substring(m.start(), m.end()));
+ }
+ }
+
+ @Test
public void testCopyConstructor() {
ServiceState serviceState = getServiceStateWithOperatorName("name", "numeric");
assertEquals(serviceState, new ServiceState(serviceState));
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
index 05a749e..468d0a5 100755
--- a/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
@@ -482,6 +482,7 @@
@Test
public void testContentProviderAccessRestriction() throws Exception {
+ if (!mTelephonyManager.isSmsCapable()) return;
Uri dummySmsUri = null;
Context context = getInstrumentation().getContext();
ContentResolver contentResolver = context.getContentResolver();
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
old mode 100644
new mode 100755
index 78561b5..e9cf4ce
--- a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -32,6 +32,7 @@
import static org.junit.Assert.fail;
import android.annotation.Nullable;
+import android.app.UiAutomation;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.ConnectivityManager;
@@ -39,6 +40,7 @@
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
+import android.net.Uri;
import android.os.Looper;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
@@ -47,6 +49,11 @@
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionPlan;
import android.telephony.TelephonyManager;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsManager;
+import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ImsRcsManager;
+import android.telephony.ims.RcsUceAdapter;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -61,6 +68,8 @@
import org.junit.BeforeClass;
import org.junit.Test;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.time.Period;
import java.time.ZonedDateTime;
import java.util.ArrayList;
@@ -79,7 +88,13 @@
public class SubscriptionManagerTest {
private static final String TAG = "SubscriptionManagerTest";
+ private static final String MODIFY_PHONE_STATE = "android.permission.MODIFY_PHONE_STATE";
private SubscriptionManager mSm;
+ private static final List<Uri> CONTACTS = new ArrayList<>();
+ static {
+ CONTACTS.add(Uri.fromParts("tel", "+16505551212", null));
+ CONTACTS.add(Uri.fromParts("tel", "+16505552323", null));
+ }
private int mSubId;
private String mPackageName;
@@ -751,6 +766,8 @@
// not treating this as test failure as it may be due to UX confirmation or may not
// be supported
Log.e(TAG, "setSubscriptionEnabled() did not complete");
+ executeWithShellPermissionAndDefault(false, mSm,
+ (sm) -> sm.setSubscriptionEnabled(mSubId, enabled));
return;
}
@@ -824,6 +841,153 @@
setPreferredDataSubId(preferredSubId);
}
+ @Test
+ public void testRestoreAllSimSpecificSettingsFromBackup() throws Exception {
+ if (!isSupported()) return;
+
+ int activeDataSubId = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
+ (sm) -> sm.getActiveDataSubscriptionId());
+ assertNotEquals(activeDataSubId, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ SubscriptionInfo activeSubInfo = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
+ (sm) -> sm.getActiveSubscriptionInfo(activeDataSubId));
+ String isoCountryCode = activeSubInfo.getCountryIso();
+
+ byte[] backupData = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
+ (sm) -> sm.getAllSimSpecificSettingsForBackup());
+ assertTrue(backupData.length > 0);
+
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, true);
+ bundle.putBoolean(CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL, false);
+ overrideCarrierConfig(bundle, activeDataSubId);
+
+ // Get the original ims values.
+ ImsManager imsManager = InstrumentationRegistry.getContext().getSystemService(
+ ImsManager.class);
+ ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(activeDataSubId);
+ boolean isVolteVtEnabledOriginal = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mMmTelManager, (m) -> m.isAdvancedCallingSettingEnabled());
+ boolean isVtImsEnabledOriginal = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mMmTelManager, (m) -> m.isVtSettingEnabled());
+ boolean isVoWiFiSettingEnabledOriginal =
+ ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mMmTelManager, (m) -> m.isVoWiFiSettingEnabled());
+ int voWifiModeOriginal = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mMmTelManager, (m) -> m.getVoWiFiModeSetting());
+ int voWiFiRoamingModeOriginal = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mMmTelManager, (m) -> m.getVoWiFiRoamingModeSetting());
+
+ // Get the original RcsUce values.
+ ImsRcsManager imsRcsManager = imsManager.getImsRcsManager(activeDataSubId);
+ RcsUceAdapter rcsUceAdapter = imsRcsManager.getUceAdapter();
+ boolean isImsRcsUceEnabledOriginal =
+ ShellIdentityUtils.invokeThrowableMethodWithShellPermissions(
+ rcsUceAdapter, (a) -> a.isUceSettingEnabled(), ImsException.class,
+ android.Manifest.permission.READ_PHONE_STATE);
+
+ //Change values in DB.
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setAdvancedCallingSettingEnabled(!isVolteVtEnabledOriginal));
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setVtSettingEnabled(!isVtImsEnabledOriginal));
+ ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(
+ rcsUceAdapter, (a) -> a.setUceSettingEnabled(!isImsRcsUceEnabledOriginal),
+ ImsException.class);
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setVoWiFiSettingEnabled(!isVoWiFiSettingEnabledOriginal));
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setVoWiFiModeSetting((voWifiModeOriginal + 1) % 3));
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mMmTelManager,
+ (m) -> m.setVoWiFiRoamingModeSetting((voWiFiRoamingModeOriginal + 1) % 3));
+
+ // Restore back to original values.
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
+ (sm) -> sm.restoreAllSimSpecificSettingsFromBackup(backupData));
+
+ // Get ims values to verify with.
+ boolean isVolteVtEnabledAfterRestore = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mMmTelManager, (m) -> m.isAdvancedCallingSettingEnabled());
+ boolean isVtImsEnabledAfterRestore = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mMmTelManager, (m) -> m.isVtSettingEnabled());
+ boolean isVoWiFiSettingEnabledAfterRestore =
+ ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mMmTelManager, (m) -> m.isVoWiFiSettingEnabled());
+ int voWifiModeAfterRestore = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mMmTelManager, (m) -> m.getVoWiFiModeSetting());
+ int voWiFiRoamingModeAfterRestore = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mMmTelManager, (m) -> m.getVoWiFiRoamingModeSetting());
+ // Get RcsUce values to verify with.
+ boolean isImsRcsUceEnabledAfterRestore =
+ ShellIdentityUtils.invokeThrowableMethodWithShellPermissions(
+ rcsUceAdapter, (a) -> a.isUceSettingEnabled(), ImsException.class,
+ android.Manifest.permission.READ_PHONE_STATE);
+
+ assertEquals(isVolteVtEnabledOriginal, isVolteVtEnabledAfterRestore);
+ if (isoCountryCode == null || isoCountryCode.equals("us") || isoCountryCode.equals("ca")) {
+ assertEquals(!isVoWiFiSettingEnabledOriginal, isVoWiFiSettingEnabledAfterRestore);
+ } else {
+ assertEquals(isVoWiFiSettingEnabledOriginal, isVoWiFiSettingEnabledAfterRestore);
+ }
+ assertEquals(voWifiModeOriginal, voWifiModeAfterRestore);
+ assertEquals(voWiFiRoamingModeOriginal, voWiFiRoamingModeAfterRestore);
+ assertEquals(isVtImsEnabledOriginal, isVtImsEnabledAfterRestore);
+ assertEquals(isImsRcsUceEnabledOriginal, isImsRcsUceEnabledAfterRestore);
+
+ // restore original carrier config.
+ overrideCarrierConfig(null, activeDataSubId);
+
+
+ try {
+ // Check api call will fail without proper permissions.
+ mSm.restoreAllSimSpecificSettingsFromBackup(backupData);
+ fail("SecurityException expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testSetAndGetD2DStatusSharing() {
+ UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ uiAutomation.adoptShellPermissionIdentity(MODIFY_PHONE_STATE);
+ int originalD2DStatusSharing = mSm.getDeviceToDeviceStatusSharing(mSubId);
+ mSm.setDeviceToDeviceStatusSharing(SubscriptionManager.D2D_SHARING_ALL_CONTACTS, mSubId);
+ assertEquals(SubscriptionManager.D2D_SHARING_ALL_CONTACTS,
+ mSm.getDeviceToDeviceStatusSharing(mSubId));
+ mSm.setDeviceToDeviceStatusSharing(SubscriptionManager.D2D_SHARING_ALL, mSubId);
+ assertEquals(SubscriptionManager.D2D_SHARING_ALL,
+ mSm.getDeviceToDeviceStatusSharing(mSubId));
+ mSm.setDeviceToDeviceStatusSharing(originalD2DStatusSharing, mSubId);
+ uiAutomation.dropShellPermissionIdentity();
+ }
+
+ @Test
+ public void testSetAndGetD2DSharingContacts() {
+ UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ uiAutomation.adoptShellPermissionIdentity(MODIFY_PHONE_STATE);
+ List<Uri> originalD2DSharingContacts = mSm.getDeviceToDeviceStatusSharingContacts(mSubId);
+ mSm.setDeviceToDeviceStatusSharingContacts(CONTACTS, mSubId);
+ assertEquals(CONTACTS, mSm.getDeviceToDeviceStatusSharingContacts(mSubId));
+ mSm.setDeviceToDeviceStatusSharingContacts(originalD2DSharingContacts, mSubId);
+ uiAutomation.dropShellPermissionIdentity();
+ }
+
+ @Nullable
+ private PersistableBundle getBundleFromBackupData(byte[] data) {
+ try (ByteArrayInputStream bis = new ByteArrayInputStream(data)) {
+ return PersistableBundle.readFromStream(bis);
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ private void overrideCarrierConfig(PersistableBundle bundle, int subId) throws Exception {
+ CarrierConfigManager carrierConfigManager = InstrumentationRegistry.getContext()
+ .getSystemService(CarrierConfigManager.class);
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(carrierConfigManager,
+ (m) -> m.overrideConfig(subId, bundle));
+ }
+
private void setPreferredDataSubId(int subId) {
final LinkedBlockingQueue<Integer> resultQueue = new LinkedBlockingQueue<>(1);
Executor executor = (command)-> command.run();
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyCallbackTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyCallbackTest.java
index 071f331..fbd2a12 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyCallbackTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyCallbackTest.java
@@ -38,6 +38,7 @@
import android.telephony.CellIdentity;
import android.telephony.CellInfo;
import android.telephony.CellLocation;
+import android.telephony.LinkCapacityEstimate;
import android.telephony.PhysicalChannelConfig;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
@@ -94,10 +95,14 @@
private boolean mOnTelephonyDisplayInfoChanged;
private boolean mOnPhysicalChannelConfigCalled;
private boolean mOnDataEnabledChangedCalled;
+ private boolean mOnLinkCapacityEstimateChangedCalled;
@RadioPowerState
private int mRadioPowerState;
@SimActivationState
private int mVoiceActivationState;
+ private boolean mOnAllowedNetworkTypesChangedCalled;
+ private int mAllowedNetworkTypeReason;
+ private long mAllowedNetworkTypeValue;
private BarringInfo mBarringInfo;
private PreciseDataConnectionState mPreciseDataConnectionState;
private PreciseCallState mPreciseCallState;
@@ -1311,4 +1316,109 @@
// Test unregister
unRegisterTelephonyCallback(mOnDataEnabledChangedCalled, mDataEnabledCallback);
}
+
+ private AllowedNetworkTypesListener mAllowedNetworkTypesCallback;
+
+ private class AllowedNetworkTypesListener extends TelephonyCallback
+ implements TelephonyCallback.AllowedNetworkTypesListener {
+ @Override
+ public void onAllowedNetworkTypesChanged(int reason, long allowedNetworkType) {
+ synchronized (mLock) {
+ mAllowedNetworkTypeReason = reason;
+ mAllowedNetworkTypeValue = allowedNetworkType;
+ mOnAllowedNetworkTypesChangedCalled = true;
+
+ mLock.notify();
+ }
+ }
+ }
+
+ @Test
+ public void testOnAllowedNetworkTypesChangedByRegisterPhoneStateListener() throws Throwable {
+ assertFalse(mOnAllowedNetworkTypesChangedCalled);
+
+ mHandler.post(() -> {
+ mAllowedNetworkTypesCallback = new AllowedNetworkTypesListener();
+ registerTelephonyCallbackWithPermission(mAllowedNetworkTypesCallback);
+ });
+
+ long originalAllowedNetworkTypeUser = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> {
+ return tm.getAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER);
+ }
+ );
+
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+ mTelephonyManager,
+ (tm) -> tm.setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER,
+ TelephonyManager.NETWORK_TYPE_BITMASK_NR));
+
+ synchronized (mLock) {
+ if (!mOnAllowedNetworkTypesChangedCalled) {
+ mLock.wait(WAIT_TIME);
+ }
+ }
+
+ long allowedNetworkTypeUser = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> {
+ return tm.getAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER);
+ }
+ );
+
+ assertEquals(TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER, mAllowedNetworkTypeReason);
+ assertEquals(allowedNetworkTypeUser, mAllowedNetworkTypeValue);
+ // Test unregister
+ unRegisterTelephonyCallback(mOnAllowedNetworkTypesChangedCalled,
+ mAllowedNetworkTypesCallback);
+
+ // Recover the allowed network type user settings.
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+ mTelephonyManager,
+ (tm) -> tm.setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER,
+ originalAllowedNetworkTypeUser));
+ }
+
+ private LinkCapacityEstimateChangedListener mLinkCapacityEstimateChangedListener;
+
+ private class LinkCapacityEstimateChangedListener extends TelephonyCallback
+ implements TelephonyCallback.LinkCapacityEstimateChangedListener {
+ @Override
+ public void onLinkCapacityEstimateChanged(
+ List<LinkCapacityEstimate> linkCapacityEstimateList) {
+ synchronized (mLock) {
+ mOnLinkCapacityEstimateChangedCalled = true;
+ mLock.notify();
+ }
+ }
+ }
+
+ @Test
+ public void testOnLinkCapacityEstimateChangedByRegisterPhoneStateListener() throws Throwable {
+ if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
+ Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+ return;
+ }
+
+ assertFalse(mOnLinkCapacityEstimateChangedCalled);
+ mHandler.post(() -> {
+ mLinkCapacityEstimateChangedListener = new LinkCapacityEstimateChangedListener();
+ registerTelephonyCallbackWithPermission(mLinkCapacityEstimateChangedListener);
+ });
+
+ synchronized (mLock) {
+ while (!mOnLinkCapacityEstimateChangedCalled) {
+ mLock.wait(WAIT_TIME);
+ }
+ }
+ assertTrue(mOnLinkCapacityEstimateChangedCalled);
+
+ // Test unregister
+ unRegisterTelephonyCallback(mOnLinkCapacityEstimateChangedCalled,
+ mLinkCapacityEstimateChangedListener);
+ }
+
}
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 dbb9cc9..6295762 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -56,7 +56,6 @@
import android.telephony.CallAttributes;
import android.telephony.CallForwardingInfo;
import android.telephony.CallQuality;
-import android.telephony.CarrierBandwidth;
import android.telephony.CarrierConfigManager;
import android.telephony.CellIdentity;
import android.telephony.CellIdentityLte;
@@ -184,6 +183,11 @@
private static final int MAX_FPLMN_NUM = 100;
private static final int MIN_FPLMN_NUM = 3;
+ private static final String THERMAL_MITIGATION_COMMAND_BASE = "cmd phone thermal-mitigation ";
+ private static final String ALLOW_PACKAGE_SUBCOMMAND = "allow-package ";
+ private static final String DISALLOW_PACKAGE_SUBCOMMAND = "disallow-package ";
+ private static final String TELEPHONY_CTS_PACKAGE = "android.telephony.cts";
+
private static final String TEST_FORWARD_NUMBER = "54321";
private static final String TESTING_PLMN = "12345";
@@ -282,6 +286,12 @@
if (mIsAllowedNetworkTypeChanged) {
recoverAllowedNetworkType();
}
+
+ StringBuilder cmdBuilder = new StringBuilder();
+ cmdBuilder.append(THERMAL_MITIGATION_COMMAND_BASE).append(DISALLOW_PACKAGE_SUBCOMMAND)
+ .append(TELEPHONY_CTS_PACKAGE);
+ TelephonyUtils.executeShellCommand(InstrumentationRegistry.getInstrumentation(),
+ cmdBuilder.toString());
}
private void saveAllowedNetworkTypesForAllReasons() {
@@ -307,12 +317,20 @@
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER);
}
);
+ long allowedNetworkTypesEnable2g = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> {
+ return tm.getAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G);
+ }
+ );
mAllowedNetworkTypesList.put(TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER,
allowedNetworkTypesUser);
mAllowedNetworkTypesList.put(TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER,
allowedNetworkTypesPower);
mAllowedNetworkTypesList.put(TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER,
allowedNetworkTypesCarrier);
+ mAllowedNetworkTypesList.put(TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G,
+ allowedNetworkTypesEnable2g);
}
private void recoverAllowedNetworkType() {
@@ -2846,6 +2864,8 @@
long allowedNetworkTypes3 = TelephonyManager.NETWORK_TYPE_BITMASK_NR
| TelephonyManager.NETWORK_TYPE_BITMASK_LTE
| TelephonyManager.NETWORK_TYPE_BITMASK_UMTS;
+ long allowedNetworkTypes4 = TelephonyManager.NETWORK_TYPE_LTE
+ | TelephonyManager.NETWORK_TYPE_EVDO_B;
try {
mIsAllowedNetworkTypeChanged = true;
@@ -2865,6 +2885,11 @@
(tm) -> tm.setAllowedNetworkTypesForReason(
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER,
allowedNetworkTypes3));
+ ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+ mTelephonyManager,
+ (tm) -> tm.setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G,
+ allowedNetworkTypes4));
long deviceAllowedNetworkTypes1 = ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, (tm) -> {
return tm.getAllowedNetworkTypesForReason(
@@ -2883,9 +2908,16 @@
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER);
}
);
+ long deviceAllowedNetworkTypes4 = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> {
+ return tm.getAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G);
+ }
+ );
assertEquals(allowedNetworkTypes1, deviceAllowedNetworkTypes1);
assertEquals(allowedNetworkTypes2, deviceAllowedNetworkTypes2);
assertEquals(allowedNetworkTypes3, deviceAllowedNetworkTypes3);
+ assertEquals(allowedNetworkTypes4, deviceAllowedNetworkTypes4);
} catch (SecurityException se) {
fail("testSetAllowedNetworkTypes: SecurityException not expected");
}
@@ -3379,23 +3411,6 @@
}
@Test
- public void testGetCarrierBandwidth() {
- if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
- return;
- }
- CarrierBandwidth bandwidth =
- ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
- (tm) -> tm.getCarrierBandwidth());
- if (mRadioVersion >= RADIO_HAL_VERSION_1_6) {
- assertTrue(bandwidth != null);
- assertTrue(bandwidth.getPrimaryDownlinkCapacityKbps()
- != CarrierBandwidth.INVALID);
- assertTrue(bandwidth.getPrimaryUplinkCapacityKbps()
- != CarrierBandwidth.INVALID);
- }
- }
-
- @Test
public void testSetSignalStrengthUpdateRequest_nullRequest() {
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
Log.d(TAG, "skipping test on device without FEATURE_TELEPHONY present");
@@ -3720,15 +3735,27 @@
}
@Test
- public void testSendThermalMitigationRequest() {
+ public void testSendThermalMitigationRequest() throws Exception {
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
return;
}
+
+ StringBuilder cmdBuilder = new StringBuilder();
+ cmdBuilder.append(THERMAL_MITIGATION_COMMAND_BASE).append(ALLOW_PACKAGE_SUBCOMMAND)
+ .append(TELEPHONY_CTS_PACKAGE);
+ TelephonyUtils.executeShellCommand(InstrumentationRegistry.getInstrumentation(),
+ cmdBuilder.toString());
+
long arbitraryCompletionWindowSecs = 1L;
+ boolean isDataThrottlingSupported = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.isRadioInterfaceCapabilitySupported(
+ TelephonyManager.CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING));
- // Test a proper data throttling thermal mitigation request.
- int thermalMitigationResult = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ int thermalMitigationResult = -1;
+ if (isDataThrottlingSupported) {
+ // Test a proper data throttling thermal mitigation request.
+ thermalMitigationResult = ShellIdentityUtils.invokeMethodWithShellPermissions(
mTelephonyManager, (tm) -> tm.sendThermalMitigationRequest(
new ThermalMitigationRequest.Builder()
.setThermalMitigationAction(ThermalMitigationRequest
@@ -3739,8 +3766,7 @@
.setCompletionDurationMillis(arbitraryCompletionWindowSecs)
.build())
.build()));
- // Only verify the result for supported devices on IRadio 1.6+
- if (mRadioVersion >= RADIO_HAL_VERSION_1_6) {
+
assertEquals(thermalMitigationResult,
TelephonyManager.THERMAL_MITIGATION_RESULT_SUCCESS);
}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/VopsSupportInfoTest.java b/tests/tests/telephony/current/src/android/telephony/cts/VopsSupportInfoTest.java
new file mode 100644
index 0000000..431da5e
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/VopsSupportInfoTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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.telephony.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.telephony.LteVopsSupportInfo;
+import android.telephony.NrVopsSupportInfo;
+import android.telephony.VopsSupportInfo;
+
+import org.junit.Test;
+
+public class VopsSupportInfoTest {
+
+ private static final int[] NR_VOPS_VALUE = {
+ NrVopsSupportInfo.NR_STATUS_VOPS_NOT_SUPPORTED,
+ NrVopsSupportInfo.NR_STATUS_VOPS_3GPP_SUPPORTED,
+ NrVopsSupportInfo.NR_STATUS_VOPS_NON_3GPP_SUPPORTED};
+ private static final int[] NR_EMC_VALUE = {
+ NrVopsSupportInfo.NR_STATUS_EMC_NOT_SUPPORTED,
+ NrVopsSupportInfo.NR_STATUS_EMC_5GCN_ONLY,
+ NrVopsSupportInfo.NR_STATUS_EMC_EUTRA_5GCN_ONLY,
+ NrVopsSupportInfo.NR_STATUS_EMC_NR_EUTRA_5GCN};
+ private static final int[] NR_EMF_VALUE = {
+ NrVopsSupportInfo.NR_STATUS_EMF_NOT_SUPPORTED,
+ NrVopsSupportInfo.NR_STATUS_EMF_5GCN_ONLY,
+ NrVopsSupportInfo.NR_STATUS_EMF_EUTRA_5GCN_ONLY,
+ NrVopsSupportInfo.NR_STATUS_EMF_NR_EUTRA_5GCN};
+
+ @Test
+ public void testLteVopsSupportInfoApi() {
+ VopsSupportInfo vops = new LteVopsSupportInfo(
+ LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED,
+ LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED);
+
+ assertEquals(LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED,
+ ((LteVopsSupportInfo) vops).getVopsSupport());
+ assertEquals(LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED,
+ ((LteVopsSupportInfo) vops).getEmcBearerSupport());
+ assertFalse(vops.isVopsSupported());
+ assertFalse(vops.isEmergencyServiceSupported());
+ assertFalse(vops.isEmergencyServiceFallbackSupported());
+
+ vops = new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_SUPPORTED,
+ LteVopsSupportInfo.LTE_STATUS_SUPPORTED);
+
+ assertEquals(LteVopsSupportInfo.LTE_STATUS_SUPPORTED,
+ ((LteVopsSupportInfo) vops).getVopsSupport());
+ assertEquals(LteVopsSupportInfo.LTE_STATUS_SUPPORTED,
+ ((LteVopsSupportInfo) vops).getEmcBearerSupport());
+ assertTrue(vops.isVopsSupported());
+ assertTrue(vops.isEmergencyServiceSupported());
+ assertFalse(vops.isEmergencyServiceFallbackSupported());
+ }
+
+ @Test
+ public void testLteVopsSupportInfoParcel() {
+ LteVopsSupportInfo vops = new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_SUPPORTED,
+ LteVopsSupportInfo.LTE_STATUS_SUPPORTED);
+
+ Parcel vopsParcel = Parcel.obtain();
+ vops.writeToParcel(vopsParcel, 0);
+ vopsParcel.setDataPosition(0);
+ LteVopsSupportInfo checkLteVops =
+ LteVopsSupportInfo.CREATOR.createFromParcel(vopsParcel);
+
+ assertEquals(0, vops.describeContents());
+ assertEquals(vops, checkLteVops);
+ }
+
+ @Test
+ public void testNrVopsSupportInfoApi() {
+ for (int i = 0; i < NR_VOPS_VALUE.length; i++) {
+ for (int j = 0; j < NR_EMC_VALUE.length; j++) {
+ for (int k = 0; k < NR_EMF_VALUE.length; k++) {
+ VopsSupportInfo vops = new NrVopsSupportInfo(NR_VOPS_VALUE[i],
+ NR_EMC_VALUE[j], NR_EMF_VALUE[k]);
+
+ assertEquals(NR_VOPS_VALUE[i], ((NrVopsSupportInfo) vops).getVopsSupport());
+ assertEquals(NR_EMC_VALUE[j], ((NrVopsSupportInfo) vops).getEmcSupport());
+ assertEquals(NR_EMF_VALUE[k], ((NrVopsSupportInfo) vops).getEmfSupport());
+ assertEquals(isVopsSupportedByNrVopsInfo(NR_VOPS_VALUE[i]),
+ vops.isVopsSupported());
+ assertEquals(isEmcSupportedByNrVopsInfo(NR_EMC_VALUE[j]),
+ vops.isEmergencyServiceSupported());
+ assertEquals(isEmfSupportedByNrVopsInfo(NR_EMF_VALUE[k]),
+ vops.isEmergencyServiceFallbackSupported());
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testNrVopsSupportInfoParcel() {
+ NrVopsSupportInfo vops = new NrVopsSupportInfo(
+ NrVopsSupportInfo.NR_STATUS_VOPS_3GPP_SUPPORTED,
+ NrVopsSupportInfo.NR_STATUS_EMC_NR_EUTRA_5GCN,
+ NrVopsSupportInfo.NR_STATUS_EMF_NR_EUTRA_5GCN);
+
+ Parcel vopsParcel = Parcel.obtain();
+ vops.writeToParcel(vopsParcel, 0);
+ vopsParcel.setDataPosition(0);
+ NrVopsSupportInfo checkNrVops =
+ NrVopsSupportInfo.CREATOR.createFromParcel(vopsParcel);
+
+ assertEquals(0, vops.describeContents());
+ assertEquals(vops, checkNrVops);
+ }
+
+ private boolean isVopsSupportedByNrVopsInfo(int value) {
+ return value != NrVopsSupportInfo.NR_STATUS_VOPS_NOT_SUPPORTED;
+ }
+
+ private boolean isEmcSupportedByNrVopsInfo(int value) {
+ return value != NrVopsSupportInfo.NR_STATUS_EMC_NOT_SUPPORTED;
+ }
+
+ private boolean isEmfSupportedByNrVopsInfo(int value) {
+ return value != NrVopsSupportInfo.NR_STATUS_EMF_NOT_SUPPORTED;
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/gba/cts/GbaServiceTest.java b/tests/tests/telephony/current/src/android/telephony/gba/cts/GbaServiceTest.java
index 64a1538..c5baf84 100644
--- a/tests/tests/telephony/current/src/android/telephony/gba/cts/GbaServiceTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/gba/cts/GbaServiceTest.java
@@ -134,6 +134,7 @@
TelephonyManager.BootstrapAuthenticationCallback() {
@Override
public void onKeysAvailable(byte[] gbaKey, String btId) {
+ super.onKeysAvailable(gbaKey, btId);
assertNotNull(gbaKey);
assertNotNull(btId);
assertArrayEquals(key, gbaKey);
@@ -146,6 +147,7 @@
@Override
public void onAuthenticationFailure(int reason) {
+ super.onAuthenticationFailure(reason);
synchronized (isSuccess) {
isFail.set(true);
isSuccess.notify();
diff --git a/tests/tests/telephony/current/src/android/telephony/gba/cts/UaSecurityProtocolIdentifierTest.java b/tests/tests/telephony/current/src/android/telephony/gba/cts/UaSecurityProtocolIdentifierTest.java
index ae1b0fd..6cfd87e 100644
--- a/tests/tests/telephony/current/src/android/telephony/gba/cts/UaSecurityProtocolIdentifierTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/gba/cts/UaSecurityProtocolIdentifierTest.java
@@ -176,6 +176,16 @@
}
}
+ @Test
+ public void testUaSecurityProtocolIdentifierBuilder() {
+ UaSecurityProtocolIdentifier sp = testCreate3GppSpId(
+ PROTO_3GPP_TLS_ID[0], TLS_CS_ID_SUPPORTED[0], false);
+ UaSecurityProtocolIdentifier.Builder builder =
+ new UaSecurityProtocolIdentifier.Builder(sp);
+
+ assertTrue(sp.equals(builder.build()));
+ }
+
private UaSecurityProtocolIdentifier testCreate3GppSpId(
Integer id, Integer cs, boolean nullExpected) {
boolean isFail = false;
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/EabControllerTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/EabControllerTest.java
index 622745b..5e0bcb0 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/EabControllerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/EabControllerTest.java
@@ -178,12 +178,12 @@
}
sServiceConnector = null;
+ overrideCarrierConfig(null);
+
if (sReceiver != null) {
InstrumentationRegistry.getInstrumentation().getContext().unregisterReceiver(sReceiver);
sReceiver = null;
}
-
- overrideCarrierConfig(null);
}
@Before
@@ -539,7 +539,7 @@
assertNotNull("Service capabilities should not be null!", capabilities);
// Verify timestamp
- assertNotNull("Timestamp should not be null!", presenceTuple.getTimestamp());
+ assertNotNull("Timestamp should not be null!", presenceTuple.getTime());
// Verify service id
assertEquals("service_id_01", presenceTuple.getServiceId());
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsRegistrationAttributesTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsRegistrationAttributesTest.java
index 55a8d0c..85b6e6d 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsRegistrationAttributesTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsRegistrationAttributesTest.java
@@ -60,6 +60,17 @@
attr.getTransportType());
assertNotNull(attr.getFeatureTags());
assertEquals(0, attr.getFeatureTags().size());
+
+ // NR
+ attr = new ImsRegistrationAttributes.Builder(
+ ImsRegistrationImplBase.REGISTRATION_TECH_NR).build();
+ assertEquals(ImsRegistrationImplBase.REGISTRATION_TECH_NR,
+ attr.getRegistrationTechnology());
+ assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+ attr.getTransportType());
+ assertEquals(0, attr.getAttributeFlags());
+ assertNotNull(attr.getFeatureTags());
+ assertEquals(0, attr.getFeatureTags().size());
}
@Test
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java
index 9b84dad..e2764f0 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceConnector.java
@@ -74,6 +74,10 @@
private static final String COMMAND_REMOVE_EAB_CONTACT = "uce remove-eab-contact ";
private static final String COMMAND_GET_UCE_ENABLED = "uce get-device-enabled";
private static final String COMMAND_SET_UCE_ENABLED = "uce set-device-enabled ";
+ private static final String COMMAND_REMOVE_UCE_REQUEST_DISALLOWED_STATUS =
+ "uce remove-request-disallowed-status ";
+ private static final String COMMAND_SET_CAPABILITY_REQUEST_TIMEOUT =
+ "uce set-capabilities-request-timeout ";
private static final String COMMAND_SET_TEST_MODE_ENABLED = "src set-test-enabled ";
private class TestCarrierServiceConnection implements ServiceConnection {
@@ -619,4 +623,18 @@
TelephonyUtils.executeShellCommand(mInstrumentation, COMMAND_BASE
+ COMMAND_SET_TEST_MODE_ENABLED + (enabled ? "true" : "false"));
}
+
+ void setCapabilitiesRequestTimeout(int slotId, long timeoutAfterMs) throws Exception {
+ StringBuilder cmdBuilder = new StringBuilder();
+ cmdBuilder.append(COMMAND_BASE).append(COMMAND_SET_CAPABILITY_REQUEST_TIMEOUT)
+ .append(COMMAND_SLOT_IDENTIFIER).append(slotId).append(" ").append(timeoutAfterMs);
+ TelephonyUtils.executeShellCommand(mInstrumentation, cmdBuilder.toString());
+ }
+
+ void removeUceRequestDisallowedStatus(int slotId) throws Exception {
+ StringBuilder cmdBuilder = new StringBuilder();
+ cmdBuilder.append(COMMAND_BASE).append(COMMAND_REMOVE_UCE_REQUEST_DISALLOWED_STATUS)
+ .append(COMMAND_SLOT_IDENTIFIER).append(slotId);
+ TelephonyUtils.executeShellCommand(mInstrumentation, cmdBuilder.toString());
+ }
}
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 829ddeb..6e0795b 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
@@ -110,30 +110,84 @@
private static final int TEST_CONFIG_VALUE_INT = 0xDEADBEEF;
private static final String TEST_CONFIG_VALUE_STRING = "DEADBEEF";
- private static final String TEST_RCS_CONFIG = "<RCSConfig>\n"
- + "\t<rcsVolteSingleRegistration>1</rcsVolteSingleRegistration>\n"
- + "\t<SERVICES>\n"
- + "\t\t<SupportedRCSProfileVersions>UP_2.0</SupportedRCSProfileVersions>\n"
- + "\t\t<ChatAuth>1</ChatAuth>\n"
- + "\t\t<GroupChatAuth>1</GroupChatAuth>\n"
- + "\t\t<ftAuth>1</ftAuth>\n"
- + "\t\t<standaloneMsgAuth>1</standaloneMsgAuth>\n"
- + "\t\t<geolocPushAuth>1<geolocPushAuth>\n"
- + "\t\t<Ext>\n"
- + "\t\t\t<DataOff>\n"
- + "\t\t\t\t<rcsMessagingDataOff>1</rcsMessagingDataOff>\n"
- + "\t\t\t\t<fileTransferDataOff>1</fileTransferDataOff>\n"
- + "\t\t\t\t<mmsDataOff>1</mmsDataOff>\n"
- + "\t\t\t\t<syncDataOff>1</syncDataOff>\n"
- + "\t\t\t</DataOff>\n"
- + "\t\t</Ext>\n"
- + "\t</SERVICES>\n"
- + "</RCSConfig>";
+ private static final String TEST_RCS_CONFIG_DEFAULT = "<?xml version=\"1.0\"?>\n"
+ + "<wap-provisioningdoc version=\"1.1\">\n"
+ + "\t<characteristic type=\"APPLICATION\">\n"
+ + "\t\t<parm name=\"AppID\" value=\"urn:oma:mo:ext-3gpp-ims:1.0\"/>\n"
+ + "\t\t<characteristic type=\"3GPP_IMS\">\n"
+ + "\t\t\t<parm name=\"AppID\" value=\"ap2001\"/>\n"
+ + "\t\t\t<parm name=\"Name\" value=\"RCS IMS Settings\"/>\n"
+ + "\t\t\t<characteristic type=\"Ext\">\n"
+ + "\t\t\t\t<characteristic type=\"GSMA\">\n"
+ + "\t\t\t\t\t<parm name=\"AppRef\" value=\"IMS-Setting\"/>\n"
+ + "\t\t\t\t\t<parm name=\"rcsVolteSingleRegistration\" value=\"1\"/>\n"
+ + "\t\t\t\t</characteristic>\n"
+ + "\t\t\t</characteristic>\n"
+ + "\t\t</characteristic>\n"
+ + "\t\t<characteristic type=\"SERVICES\">\n"
+ + "\t\t\t<parm name=\"SupportedRCSProfileVersions\" value=\"UP2.3\"/>\n"
+ + "\t\t\t<parm name=\"ChatAuth\" value=\"1\"/>\n"
+ + "\t\t\t<parm name=\"GroupChatAuth\" value=\"1\"/>\n"
+ + "\t\t\t<parm name=\"ftAuth\" value=\"1\"/>\n"
+ + "\t\t\t<parm name=\"standaloneMsgAuth\" value=\"1\"/>\n"
+ + "\t\t\t<parm name=\"geolocPushAuth\" value=\"1\"/>\n"
+ + "\t\t\t<characteristic type=\"Ext\">\n"
+ + "\t\t\t\t<characteristic type=\"DataOff\">\n"
+ + "\t\t\t\t\t<parm name=\"rcsMessagingDataOff\" value=\"1\"/>\n"
+ + "\t\t\t\t\t<parm name=\"fileTransferDataOff\" value=\"1\"/>\n"
+ + "\t\t\t\t\t<parm name=\"mmsDataOff\" value=\"1\"/>\n"
+ + "\t\t\t\t\t<parm name=\"syncDataOff\" value=\"1\"/>\n"
+ + "\t\t\t\t\t<characteristic type=\"Ext\"/>\n"
+ + "\t\t\t\t</characteristic>\n"
+ + "\t\t\t</characteristic>\n"
+ + "\t\t</characteristic>\n"
+ + "\t</characteristic>\n"
+ + "</wap-provisioningdoc>\n";
+
+ private static final String TEST_RCS_CONFIG_SINGLE_REGISTRATION_DISABLED =
+ "<?xml version=\"1.0\"?>\n"
+ + "<wap-provisioningdoc version=\"1.1\">\n"
+ + "\t<characteristic type=\"APPLICATION\">\n"
+ + "\t\t<parm name=\"AppID\" value=\"urn:oma:mo:ext-3gpp-ims:1.0\"/>\n"
+ + "\t\t<characteristic type=\"3GPP_IMS\">\n"
+ + "\t\t\t<parm name=\"AppID\" value=\"ap2001\"/>\n"
+ + "\t\t\t<parm name=\"Name\" value=\"RCS IMS Settings\"/>\n"
+ + "\t\t\t<characteristic type=\"Ext\">\n"
+ + "\t\t\t\t<characteristic type=\"GSMA\">\n"
+ + "\t\t\t\t\t<parm name=\"AppRef\" value=\"IMS-Setting\"/>\n"
+ + "\t\t\t\t\t<parm name=\"rcsVolteSingleRegistration\" value=\"0\"/>\n"
+ + "\t\t\t\t</characteristic>\n"
+ + "\t\t\t</characteristic>\n"
+ + "\t\t</characteristic>\n"
+ + "\t</characteristic>\n"
+ + "</wap-provisioningdoc>\n";
+ private static final String TEST_RCS_PRE_CONFIG = "<RCSPreProvisiniongConfig>\n"
+ + "\t<VERS>\n"
+ + "\t\t<version>1</version>\n"
+ + "\t\t<validity>1728000</validity>\n"
+ + "\t</VERS>\n"
+ + "\t<TOKEN>\n"
+ + "\t\t<token>X</token>\n"
+ + "\t</TOKEN>\n"
+ + "\t<EXT>\n"
+ + "\t\t<url>https://rcs.mnc123.mcc456.pub.3gppnetwork.org</url>\n"
+ + "\t</EXT>\n"
+ + "</RCSPreProvisiniongConfig>";
private static final int RCS_CONFIG_CB_UNKNOWN = Integer.MAX_VALUE;
private static final int RCS_CONFIG_CB_CHANGED = 0;
private static final int RCS_CONFIG_CB_ERROR = 1;
private static final int RCS_CONFIG_CB_RESET = 2;
private static final int RCS_CONFIG_CB_DELETE = 3;
+ private static final int RCS_CONFIG_CB_PREPROV = 4;
+
+ private static final String CHAT_FEATURE_TAG =
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.session\"";
+ public static final String FILE_TRANSFER_FEATURE_TAG =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.fthttp\"";
+ private static final String CHAT_SERVICE_ID =
+ "org.openmobilealliance:ChatSession";
+ private static final String FILE_TRANSFER_SERVICE_ID =
+ "org.openmobilealliance:File-Transfer-HTTP";
private static CarrierConfigReceiver sReceiver;
private static SingleRegistrationCapabilityReceiver sSrcReceiver;
@@ -857,28 +911,20 @@
assertEquals(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED, deregResult.getCode());
// Start registration
- ImsRegistrationAttributes lteTagsAttr = new ImsRegistrationAttributes.Builder(
- ImsRegistrationImplBase.REGISTRATION_TECH_LTE)
- .setFeatureTags(featureTags)
- .build();
- sServiceConnector.getCarrierService().getImsRegistration().onRegistering(lteTagsAttr);
- ImsRegistrationAttributes attrResult = waitForResult(mRegQueue);
- assertNotNull(attrResult);
- assertEquals(ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
- attrResult.getRegistrationTechnology());
- assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, attrResult.getTransportType());
- assertEquals(0, attrResult.getAttributeFlags());
- assertEquals(featureTags, attrResult.getFeatureTags());
+ verifyRegistering(ImsRegistrationImplBase.REGISTRATION_TECH_LTE, featureTags, mRegQueue,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN, 0 /*expected flags*/);
+
+ // move to NR
+ verifyRegistering(ImsRegistrationImplBase.REGISTRATION_TECH_NR, featureTags, mRegQueue,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN, 0 /*expected flags*/);
// Complete registration
- sServiceConnector.getCarrierService().getImsRegistration().onRegistered(lteTagsAttr);
- attrResult = waitForResult(mRegQueue);
- assertNotNull(attrResult);
- assertEquals(ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
- attrResult.getRegistrationTechnology());
- assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, attrResult.getTransportType());
- assertEquals(0, attrResult.getAttributeFlags());
- assertEquals(featureTags, attrResult.getFeatureTags());
+ verifyRegistered(ImsRegistrationImplBase.REGISTRATION_TECH_LTE, featureTags, mRegQueue,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN, 0 /*expected flags*/);
+
+ // move to NR
+ verifyRegistered(ImsRegistrationImplBase.REGISTRATION_TECH_NR, featureTags, mRegQueue,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN, 0 /*expected flags*/);
try {
automan.adoptShellPermissionIdentity();
@@ -1086,8 +1132,8 @@
capExchangeImpl.setPublishOperator((listener, pidfXml, cb) -> {
int networkResp = 200;
String reason = "";
- listener.onPublish();
cb.onNetworkResponse(networkResp, reason);
+ listener.onPublish();
});
// Unregister the publish state callback
@@ -1181,6 +1227,137 @@
}
@Test
+ public void testPublishImsReg() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ // Trigger carrier config changed
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putBoolean(CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONED_BOOL, false);
+ bundle.putBoolean(CarrierConfigManager.Ims.KEY_ENABLE_PRESENCE_PUBLISH_BOOL, true);
+ overrideCarrierConfig(bundle);
+
+ ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+ if (imsManager == null) {
+ fail("Cannot find IMS service");
+ }
+
+ ImsRcsManager imsRcsManager = imsManager.getImsRcsManager(sTestSub);
+ RcsUceAdapter uceAdapter = imsRcsManager.getUceAdapter();
+
+ // Connect to device ImsService with MmTel feature and RCS feature
+ triggerFrameworkConnectToImsServiceBindMmTelAndRcsFeature();
+
+ TestRcsCapabilityExchangeImpl capExchangeImpl = sServiceConnector.getCarrierService()
+ .getRcsFeature().getRcsCapabilityExchangeImpl();
+
+ // Register the callback to listen to the publish state changed
+ LinkedBlockingQueue<Integer> publishStateQueue = new LinkedBlockingQueue<>();
+ RcsUceAdapter.OnPublishStateChangedListener publishStateCallback =
+ publishStateQueue::offer;
+
+ final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ try {
+ automan.adoptShellPermissionIdentity();
+ uceAdapter.addOnPublishStateChangedListener(getContext().getMainExecutor(),
+ publishStateCallback);
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+
+ // Verify receiving the publish state callback immediately after registering the callback.
+ assertEquals(RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED,
+ waitForIntResult(publishStateQueue));
+ publishStateQueue.clear();
+
+ LinkedBlockingQueue<String> pidfQueue = new LinkedBlockingQueue<>();
+ // Setup the operation of the publish request.
+ capExchangeImpl.setPublishOperator((listener, pidfXml, cb) -> {
+ pidfQueue.offer(pidfXml);
+ int networkResp = 200;
+ String reason = "";
+ cb.onNetworkResponse(networkResp, reason);
+ listener.onPublish();
+ });
+
+ LinkedBlockingQueue<ImsRegistrationAttributes> mQueue = new LinkedBlockingQueue<>();
+ RegistrationManager.RegistrationCallback callback =
+ new RegistrationManager.RegistrationCallback() {
+ @Override
+ public void onRegistered(ImsRegistrationAttributes attr) {
+ mQueue.offer(attr);
+ }
+
+ @Override
+ public void onRegistering(ImsRegistrationAttributes attr) {}
+
+ @Override
+ public void onUnregistered(ImsReasonInfo info) {}
+
+ @Override
+ public void onTechnologyChangeFailed(int type, ImsReasonInfo info) {}
+ };
+ ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(imsRcsManager,
+ (m) -> m.registerImsRegistrationCallback(getContext().getMainExecutor(), callback),
+ ImsException.class);
+
+ // IMS registers
+ ArraySet<String> featureTags = new ArraySet<>();
+ // Chat Session
+ featureTags.add(CHAT_FEATURE_TAG);
+ featureTags.add(FILE_TRANSFER_FEATURE_TAG);
+ ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder(
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE).setFeatureTags(featureTags).build();
+ sServiceConnector.getCarrierService().getImsRegistration().onRegistered(attr);
+ waitForParam(mQueue, attr);
+
+ // Notify framework that the RCS capability status is changed and PRESENCE UCE is enabled.
+ RcsImsCapabilities capabilities =
+ new RcsImsCapabilities(RcsUceAdapter.CAPABILITY_TYPE_PRESENCE_UCE);
+ sServiceConnector.getCarrierService().getRcsFeature()
+ .notifyCapabilitiesStatusChanged(capabilities);
+
+ CapabilityExchangeEventListener eventListener =
+ sServiceConnector.getCarrierService().getRcsFeature().getEventListener();
+
+ // ImsService triggers to notify framework publish device's capabilities.
+ eventListener.onRequestPublishCapabilities(
+ RcsUceAdapter.CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN);
+
+ // Verify that the publish is triggered and receive the publish state changed callback.
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_UCE_REQUEST_PUBLISH));
+ assertEquals(RcsUceAdapter.PUBLISH_STATE_OK, waitForIntResult(publishStateQueue));
+ publishStateQueue.clear();
+
+ // Can not verify the pidf fully, but we can ensure that the service id for the feature is
+ // contained in the XML. Multible PUBLISH requests may occur based on the state of the stack
+ // at the time of this call, retry to get correct PIDF up to 5 times.
+ boolean containsChatServiceId = false;
+ boolean containsFileTransferServiceId = false;
+ for (int retry = 0; retry < 5; retry++) {
+ String pidf = waitForResult(pidfQueue);
+ if (pidf == null) break;
+ containsChatServiceId = pidf.contains(CHAT_SERVICE_ID);
+ containsFileTransferServiceId = pidf.contains(FILE_TRANSFER_SERVICE_ID);
+ if (containsChatServiceId && containsFileTransferServiceId) break;
+ }
+ assertTrue("PIDF XML doesn't contain chat service-id", containsChatServiceId);
+ assertTrue("PIDF XML doesn't contain FT service-id",
+ containsFileTransferServiceId);
+
+ // Trigger RcsFeature is unavailable
+ sServiceConnector.getCarrierService().getRcsFeature()
+ .setFeatureState(ImsFeature.STATE_UNAVAILABLE);
+
+ // Verify the RcsCapabilityExchangeImplBase will be removed.
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_UCE_LISTENER_SET));
+
+ overrideCarrierConfig(null);
+ }
+
+ @Test
public void testRcsCapabilitiesPublishNetworkResponseWithReasonHeader() throws Exception {
if (!ImsUtils.shouldTestImsService()) {
return;
@@ -1230,8 +1407,8 @@
capExchangeImpl.setPublishOperator((listener, pidfXml, cb) -> {
int networkResp = 200;
String reason = "OK";
- listener.onPublish();
cb.onNetworkResponse(networkResp, reason);
+ listener.onPublish();
});
// IMS registers
@@ -1270,8 +1447,8 @@
String reason = "";
int reasonHeaderCause = 400;
String reasonHeaderText = "Bad Request";
- listener.onPublish();
cb.onNetworkResponse(networkResp, reason, reasonHeaderCause, reasonHeaderText);
+ listener.onPublish();
});
// ImsService triggers to notify framework publish device's capabilities.
@@ -1297,6 +1474,129 @@
}
@Test
+ public void testRcsPublishThrottle() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ // Trigger carrier config change
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putBoolean(CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONED_BOOL, false);
+ bundle.putBoolean(CarrierConfigManager.Ims.KEY_ENABLE_PRESENCE_PUBLISH_BOOL, true);
+ overrideCarrierConfig(bundle);
+
+ ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+ if (imsManager == null) {
+ fail("Cannot get the ImsManager");
+ }
+ ImsRcsManager imsRcsManager = imsManager.getImsRcsManager(sTestSub);
+ RcsUceAdapter uceAdapter = imsRcsManager.getUceAdapter();
+
+ // Connect to the ImsService
+ triggerFrameworkConnectToImsServiceBindMmTelAndRcsFeature();
+
+ TestRcsCapabilityExchangeImpl capExchangeImpl = sServiceConnector.getCarrierService()
+ .getRcsFeature().getRcsCapabilityExchangeImpl();
+
+ // Setup the response of the publish request.
+ capExchangeImpl.setPublishOperator((listener, pidfXml, cb) -> {
+ int networkResp = 200;
+ String reason = "OK";
+ cb.onNetworkResponse(networkResp, reason);
+ listener.onPublish();
+ });
+
+ // Register the callback to listen to the publish state changed
+ LinkedBlockingQueue<Integer> publishStateQueue = new LinkedBlockingQueue<>();
+ RcsUceAdapter.OnPublishStateChangedListener publishStateCallback =
+ new RcsUceAdapter.OnPublishStateChangedListener() {
+ public void onPublishStateChange(int state) {
+ publishStateQueue.offer(state);
+ }
+ };
+
+ final UiAutomation automation = InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation();
+ try {
+ automation.adoptShellPermissionIdentity();
+ uceAdapter.addOnPublishStateChangedListener(getContext().getMainExecutor(),
+ publishStateCallback);
+ } finally {
+ automation.dropShellPermissionIdentity();
+ }
+
+ // Verify receiving the publish state callback immediately after registering the callback.
+ assertEquals(RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED,
+ waitForIntResult(publishStateQueue));
+ publishStateQueue.clear();
+
+ // IMS registers
+ sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+
+ // Verify the PUBLISH request should not be triggered and the publish state is still
+ // NOT_PUBLISHED even the IMS is registered.
+ if (publishStateQueue.poll() != null) {
+ fail("The PUBLISH request should not be triggered.");
+ }
+ try {
+ automation.adoptShellPermissionIdentity();
+ int publishState = uceAdapter.getUcePublishState();
+ assertEquals(RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED, publishState);
+ } finally {
+ automation.dropShellPermissionIdentity();
+ }
+
+ // Notify framework that the RCS capability status is changed and PRESENCE UCE is enabled.
+ RcsImsCapabilities capabilities =
+ new RcsImsCapabilities(RcsUceAdapter.CAPABILITY_TYPE_PRESENCE_UCE);
+ sServiceConnector.getCarrierService().getRcsFeature()
+ .notifyCapabilitiesStatusChanged(capabilities);
+
+ CapabilityExchangeEventListener eventListener =
+ sServiceConnector.getCarrierService().getRcsFeature().getEventListener();
+
+ // Notify framework to send the PUBLISH request to the ImsService.
+ eventListener.onRequestPublishCapabilities(
+ RcsUceAdapter.CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN);
+
+ // Verify that ImsService received the first PUBLISH
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_UCE_REQUEST_PUBLISH));
+ assertEquals(RcsUceAdapter.PUBLISH_STATE_OK, waitForIntResult(publishStateQueue));
+ publishStateQueue.clear();
+ try {
+ automation.adoptShellPermissionIdentity();
+ int publishState = uceAdapter.getUcePublishState();
+ assertEquals(RcsUceAdapter.PUBLISH_STATE_OK, publishState);
+ } finally {
+ automation.dropShellPermissionIdentity();
+ }
+
+ // Now enable voice availability
+ sServiceConnector.getCarrierService().getMmTelFeature()
+ .notifyCapabilitiesStatusChanged(new MmTelFeature.MmTelCapabilities(
+ MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE));
+
+ // The published just succeeded. The next publish should not be triggered immediately even
+ // the device capabilities has changed. Wait 3 seconds to verify the ImsService does not
+ // receive the publish request from the framework.
+ assertFalse(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_UCE_REQUEST_PUBLISH, 3000 /* 3 seconds */));
+
+ // However, if the request is triggered from the service, a new publish request should be
+ // sent immediately.
+ eventListener.onRequestPublishCapabilities(
+ RcsUceAdapter.CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN);
+
+ // Verify the ImsService receive the publish request
+ assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+ TestImsService.LATCH_UCE_REQUEST_PUBLISH, 3000 /* Wait up to 3 seconds */));
+
+ overrideCarrierConfig(null);
+ }
+
+ @Test
public void testRcsManagerRegistrationCallback() throws Exception {
if (!ImsUtils.shouldTestImsService()) {
return;
@@ -1579,6 +1879,20 @@
verifyRegistrationState(imsRcsManager, RegistrationManager.REGISTRATION_STATE_REGISTERED);
verifyRegistrationTransportType(imsRcsManager, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ // Start registration over NR
+ sServiceConnector.getCarrierService().getImsRegistration().onRegistering(
+ ImsRegistrationImplBase.REGISTRATION_TECH_NR);
+ assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
+ verifyRegistrationState(imsRcsManager, RegistrationManager.REGISTRATION_STATE_REGISTERING);
+ verifyRegistrationTransportType(imsRcsManager, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ // Complete registration over NR
+ sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
+ ImsRegistrationImplBase.REGISTRATION_TECH_NR);
+ assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, waitForIntResult(mQueue));
+ verifyRegistrationState(imsRcsManager, RegistrationManager.REGISTRATION_STATE_REGISTERED);
+ verifyRegistrationTransportType(imsRcsManager, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
// Fail handover to IWLAN
sServiceConnector.getCarrierService().getImsRegistration().onTechnologyChangeFailed(
ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
@@ -2007,6 +2321,21 @@
automan.dropShellPermissionIdentity();
}
+ // Remove availability changed listener
+ try {
+ automan.adoptShellPermissionIdentity();
+ imsRcsManager.removeOnAvailabilityChangedListener(callback);
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+
+ // Notify capabilities status changes again.
+ sServiceConnector.getCarrierService().getRcsFeature()
+ .notifyCapabilitiesStatusChanged(optionsCap);
+
+ // The callback should not be called because the listener is removed.
+ assertTrue(availabilityChanged.isEmpty());
+
overrideCarrierConfig(null);
}
@@ -2360,7 +2689,7 @@
try {
automan.adoptShellPermissionIdentity();
provisioningManager.notifyRcsAutoConfigurationReceived(
- TEST_RCS_CONFIG.getBytes(), false);
+ TEST_RCS_CONFIG_DEFAULT.getBytes(), false);
} finally {
automan.dropShellPermissionIdentity();
}
@@ -2381,7 +2710,7 @@
assertEquals(res, RCS_CONFIG_CB_CHANGED);
RcsProvisioningCallbackParams params = waitForResult(paramsQueue);
assertNotNull(params);
- assertTrue(Arrays.equals(params.mConfig, TEST_RCS_CONFIG.getBytes()));
+ assertTrue(Arrays.equals(params.mConfig, TEST_RCS_CONFIG_DEFAULT.getBytes()));
//verify callback when rcs configuration removed
config.getIImsConfig().notifyRcsAutoConfigurationRemoved();
@@ -2390,13 +2719,13 @@
//verify callback when rcs configuration received, compressed
config.getIImsConfig().notifyRcsAutoConfigurationReceived(
- ImsUtils.compressGzip(TEST_RCS_CONFIG.getBytes()), true);
+ ImsUtils.compressGzip(TEST_RCS_CONFIG_DEFAULT.getBytes()), true);
res = waitForIntResult(actionQueue);
assertEquals(res, RCS_CONFIG_CB_CHANGED);
params = waitForResult(paramsQueue);
assertNotNull(params);
- assertTrue(Arrays.equals(params.mConfig, TEST_RCS_CONFIG.getBytes()));
+ assertTrue(Arrays.equals(params.mConfig, TEST_RCS_CONFIG_DEFAULT.getBytes()));
//verify callback when auto config error received
config.notifyAutoConfigurationErrorReceived(errorCode, errorString);
@@ -2412,6 +2741,15 @@
res = waitForIntResult(actionQueue);
assertEquals(res, RCS_CONFIG_CB_RESET);
+ //verify callback when rcs pre-provisioning configuration received
+ TestAcsClient.getInstance().notifyPreProvisioning(TEST_RCS_PRE_CONFIG.getBytes());
+
+ res = waitForIntResult(actionQueue);
+ assertEquals(res, RCS_CONFIG_CB_PREPROV);
+ params = waitForResult(paramsQueue);
+ assertNotNull(params);
+ assertTrue(Arrays.equals(params.mConfig, TEST_RCS_PRE_CONFIG.getBytes()));
+
//unregister callback and verify not to receive callback any more
try {
automan.adoptShellPermissionIdentity();
@@ -2443,7 +2781,7 @@
buildRcsProvisioningCallback(clientQueue, paramsQueue);
ProvisioningManager provisioningManager =
ProvisioningManager.createForSubscriptionId(sTestSub);
- String configStr = "<test01/>\n" + TEST_RCS_CONFIG;
+ String configStr = TEST_RCS_CONFIG_DEFAULT;
//notify rcs configuration received, wait rcs gets ready and receives notification
try {
@@ -2473,7 +2811,7 @@
assertTrue(Arrays.equals(
configStr.getBytes(), TestAcsClient.getInstance().getConfig()));
- configStr = "<test02/>\n" + TEST_RCS_CONFIG;
+ configStr = TEST_RCS_CONFIG_SINGLE_REGISTRATION_DISABLED;
try {
automan.adoptShellPermissionIdentity();
provisioningManager.notifyRcsAutoConfigurationReceived(
@@ -2514,7 +2852,7 @@
try {
automan.adoptShellPermissionIdentity();
provisioningManager.notifyRcsAutoConfigurationReceived(
- TEST_RCS_CONFIG.getBytes(), false);
+ TEST_RCS_CONFIG_DEFAULT.getBytes(), false);
} finally {
automan.dropShellPermissionIdentity();
}
@@ -2569,7 +2907,7 @@
try {
automan.adoptShellPermissionIdentity();
provisioningManager.notifyRcsAutoConfigurationReceived(
- TEST_RCS_CONFIG.getBytes(), false);
+ TEST_RCS_CONFIG_DEFAULT.getBytes(), false);
} finally {
automan.dropShellPermissionIdentity();
}
@@ -2623,6 +2961,11 @@
assertEquals(false, (ProvisioningManager.STATUS_CARRIER_NOT_CAPABLE & capability) == 0);
try {
automan.adoptShellPermissionIdentity();
+ //set the rcs config with single registration enabled
+ provisioningManager.notifyRcsAutoConfigurationReceived(
+ TEST_RCS_CONFIG_DEFAULT.getBytes(), false);
+ int res = waitForIntResult(TestAcsClient.getInstance().getActionQueue());
+ assertEquals(res, TestAcsClient.ACTION_CONFIG_CHANGED);
assertEquals(provisioningManager.isRcsVolteSingleRegistrationCapable(),
(ProvisioningManager.STATUS_CARRIER_NOT_CAPABLE & capability) == 0);
} finally {
@@ -2660,6 +3003,31 @@
automan.dropShellPermissionIdentity();
}
+ sSrcReceiver.clearQueue();
+ sServiceConnector.setDeviceSingleRegistrationEnabled(true);
+ sSrcReceiver.waitForChanged();
+ capability = sSrcReceiver.getCapability();
+
+ assertEquals(true, (ProvisioningManager.STATUS_DEVICE_NOT_CAPABLE & capability) == 0);
+ try {
+ automan.adoptShellPermissionIdentity();
+ assertEquals(provisioningManager.isRcsVolteSingleRegistrationCapable(), true);
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+
+ try {
+ automan.adoptShellPermissionIdentity();
+ //set the rcs config with single registration disabled
+ provisioningManager.notifyRcsAutoConfigurationReceived(
+ TEST_RCS_CONFIG_SINGLE_REGISTRATION_DISABLED.getBytes(), false);
+ int res = waitForIntResult(TestAcsClient.getInstance().getActionQueue());
+ assertEquals(res, TestAcsClient.ACTION_CONFIG_CHANGED);
+ assertEquals(provisioningManager.isRcsVolteSingleRegistrationCapable(), false);
+ } finally {
+ automan.dropShellPermissionIdentity();
+ }
+
sServiceConnector.setDeviceSingleRegistrationEnabled(null);
overrideCarrierConfig(null);
}
@@ -2794,6 +3162,7 @@
return new ProvisioningManager.RcsProvisioningCallback() {
@Override
public void onConfigurationChanged(byte[] configXml) {
+ super.onConfigurationChanged(configXml);
actionQueue.offer(RCS_CONFIG_CB_CHANGED);
if (paramQueue != null) {
RcsProvisioningCallbackParams params = new RcsProvisioningCallbackParams();
@@ -2804,6 +3173,7 @@
@Override
public void onAutoConfigurationErrorReceived(int code, String str) {
+ super.onAutoConfigurationErrorReceived(code, str);
actionQueue.offer(RCS_CONFIG_CB_ERROR);
if (paramQueue != null) {
RcsProvisioningCallbackParams params = new RcsProvisioningCallbackParams();
@@ -2815,13 +3185,26 @@
@Override
public void onConfigurationReset() {
+ super.onConfigurationReset();
actionQueue.offer(RCS_CONFIG_CB_RESET);
}
@Override
public void onRemoved() {
+ super.onRemoved();
actionQueue.offer(RCS_CONFIG_CB_DELETE);
}
+
+ @Override
+ public void onPreProvisioningReceived(byte[] configXml) {
+ super.onPreProvisioningReceived(configXml);
+ actionQueue.offer(RCS_CONFIG_CB_PREPROV);
+ if (paramQueue != null) {
+ RcsProvisioningCallbackParams params = new RcsProvisioningCallbackParams();
+ params.mConfig = configXml;
+ paramQueue.offer(params);
+ }
+ }
};
}
// Waiting for ImsRcsManager to become public before implementing RegistrationManager,
@@ -2868,6 +3251,34 @@
assertEquals(expectedTransportType, waitForIntResult(mQueue));
}
+ private void verifyRegistering(int tech, ArraySet<String> featureTags,
+ LinkedBlockingQueue<ImsRegistrationAttributes> attrQueue, int expectedTransport,
+ int expectedAttrFlags) throws Exception {
+ ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder(tech)
+ .setFeatureTags(featureTags).build();
+ sServiceConnector.getCarrierService().getImsRegistration().onRegistering(attr);
+ ImsRegistrationAttributes attrResult = waitForResult(attrQueue);
+ assertNotNull(attrResult);
+ assertEquals(tech, attrResult.getRegistrationTechnology());
+ assertEquals(expectedTransport, attrResult.getTransportType());
+ assertEquals(expectedAttrFlags, attrResult.getAttributeFlags());
+ assertEquals(featureTags, attrResult.getFeatureTags());
+ }
+
+ private void verifyRegistered(int tech, ArraySet<String> featureTags,
+ LinkedBlockingQueue<ImsRegistrationAttributes> attrQueue, int expectedTransport,
+ int expectedAttrFlags) throws Exception {
+ ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder(tech)
+ .setFeatureTags(featureTags).build();
+ sServiceConnector.getCarrierService().getImsRegistration().onRegistered(attr);
+ ImsRegistrationAttributes attrResult = waitForResult(attrQueue);
+ assertNotNull(attrResult);
+ assertEquals(tech, attrResult.getRegistrationTechnology());
+ assertEquals(expectedTransport, attrResult.getTransportType());
+ assertEquals(expectedAttrFlags, attrResult.getAttributeFlags());
+ assertEquals(featureTags, attrResult.getFeatureTags());
+ }
+
private <T> boolean waitForParam(LinkedBlockingQueue<T> queue, T waitParam) throws Exception {
T result;
while ((result = waitForResult(queue)) != null) {
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java
index 180f375..42fb83a 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsUtils.java
@@ -24,7 +24,6 @@
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
-import android.telephony.ims.SipMessage;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -39,7 +38,7 @@
import java.util.zip.GZIPOutputStream;
public class ImsUtils {
- public static final boolean VDBG = false;
+ public static final boolean VDBG = true;
// ImsService rebind has an exponential backoff capping at 64 seconds. Wait for 70 seconds to
// allow for the new poll to happen in the framework.
@@ -49,10 +48,6 @@
public static final int ITEM_NON_COMPRESSED = 2000;
// Id for compressed auto configuration xml.
public static final int ITEM_COMPRESSED = 2001;
- // TODO Replace with a real sip message once that logic is in.
- public static final String TEST_TRANSACTION_ID = "z9hG4bK.TeSt";
- public static final String TEST_CALL_ID = "testcall";
- public static final SipMessage TEST_SIP_MESSAGE = new SipMessage("A", "B", new byte[0]);
public static boolean shouldTestTelephony() {
final PackageManager pm = InstrumentationRegistry.getInstrumentation().getContext()
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsClientConfigurationTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsClientConfigurationTest.java
new file mode 100644
index 0000000..f1a09de
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsClientConfigurationTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.telephony.ims.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.telephony.ims.RcsClientConfiguration;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public final class RcsClientConfigurationTest {
+
+ private static final String RCS_VERSION = "9.0";
+ private static final String RCS_PROFILE = RcsClientConfiguration.RCS_PROFILE_2_3;
+ private static final String CLIENT_VENDOR = "Android";
+ private static final String CLIENT_VERSION = "RCSAndrd-1.0";
+
+ @Test
+ public void testRcsClientConfigurationApi() {
+ RcsClientConfiguration rcc = new RcsClientConfiguration(
+ RCS_VERSION, RCS_PROFILE, CLIENT_VENDOR, CLIENT_VERSION);
+
+ assertEquals(RCS_VERSION, rcc.getRcsVersion());
+ assertEquals(RCS_PROFILE, rcc.getRcsProfile());
+ assertEquals(CLIENT_VENDOR, rcc.getClientVendor());
+ assertEquals(CLIENT_VERSION, rcc.getClientVersion());
+ }
+
+ @Test
+ public void testRcsClientConfigurationParcel() {
+ RcsClientConfiguration rcc = new RcsClientConfiguration(
+ RCS_VERSION, RCS_PROFILE, CLIENT_VENDOR, CLIENT_VERSION);
+ Parcel rccParcel = Parcel.obtain();
+ rcc.writeToParcel(rccParcel, 0);
+ rccParcel.setDataPosition(0);
+ RcsClientConfiguration checkRcc =
+ RcsClientConfiguration.CREATOR.createFromParcel(rccParcel);
+
+ assertEquals(0, rcc.describeContents());
+ assertEquals(rcc, checkRcc);
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsContactUceCapabilityTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsContactUceCapabilityTest.java
index 4cf7a62..4fcc85b 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsContactUceCapabilityTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsContactUceCapabilityTest.java
@@ -17,13 +17,16 @@
package android.telephony.ims.cts;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.net.Uri;
import android.os.Parcel;
import android.telephony.ims.RcsContactPresenceTuple;
import android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities;
import android.telephony.ims.RcsContactUceCapability;
+import android.telephony.ims.RcsContactUceCapability.OptionsBuilder;
import android.telephony.ims.RcsContactUceCapability.PresenceBuilder;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -31,12 +34,29 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.time.Instant;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
+import java.util.Set;
@RunWith(AndroidJUnit4.class)
public class RcsContactUceCapabilityTest {
- private static final Uri TEST_CONTACT = Uri.fromParts("sip", "me.test", null);
+ private static final Uri TEST_CONTACT = Uri.fromParts("sip", "test1", null);
+
+ public static final String FEATURE_TAG_CHAT_IM =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.im\"";
+
+ public static final String FEATURE_TAG_CHAT_SESSION =
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.session\"";
+
+ public static final String FEATURE_TAG_FILE_TRANSFER =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.fthttp\"";
+
+ public static final String FEATURE_TAG_POST_CALL =
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.gsma.callunanswered\"";
@Test
public void testParcelUnparcel() {
@@ -44,29 +64,17 @@
return;
}
- final boolean isAudioCapable = true;
- final boolean isVideoCapable = true;
- final String serviceVersion = "1.0";
- final String serviceDescription = "service description test";
-
- // Create the test capability
- ServiceCapabilities.Builder servCapsBuilder = new ServiceCapabilities.Builder(
- isAudioCapable, isVideoCapable);
- servCapsBuilder.addSupportedDuplexMode(ServiceCapabilities.DUPLEX_MODE_FULL);
-
- RcsContactPresenceTuple.Builder tupleBuilder = new RcsContactPresenceTuple.Builder(
- RcsContactPresenceTuple.TUPLE_BASIC_STATUS_OPEN,
- RcsContactPresenceTuple.SERVICE_ID_MMTEL, serviceVersion);
- tupleBuilder.setContactUri(TEST_CONTACT)
- .setServiceDescription(serviceDescription)
- .setServiceCapabilities(servCapsBuilder.build());
+ // Create two presence tuples for testing.
+ RcsContactPresenceTuple mmtelTuple = createPresenceMmtelTuple();
+ RcsContactPresenceTuple ftTuple = createPresenceFtTuple();
PresenceBuilder presenceBuilder = new PresenceBuilder(TEST_CONTACT,
RcsContactUceCapability.SOURCE_TYPE_CACHED,
RcsContactUceCapability.REQUEST_RESULT_FOUND);
- presenceBuilder.addCapabilityTuple(tupleBuilder.build());
+ presenceBuilder.addCapabilityTuple(mmtelTuple);
+ presenceBuilder.addCapabilityTuples(Collections.singletonList(ftTuple));
- RcsContactUceCapability testCapability = presenceBuilder.build();
+ final RcsContactUceCapability testCapability = presenceBuilder.build();
// parcel and unparcel
Parcel infoParceled = Parcel.obtain();
@@ -76,35 +84,134 @@
RcsContactUceCapability.CREATOR.createFromParcel(infoParceled);
infoParceled.recycle();
- boolean unparceledVolteCapable = false;
- boolean unparceledVtCapable = false;
- String unparceledTupleStatus = RcsContactPresenceTuple.TUPLE_BASIC_STATUS_CLOSED;
- String unparceledDuplexMode = ServiceCapabilities.DUPLEX_MODE_RECEIVE_ONLY;
+ assertEquals(unparceledCapability.getContactUri(), testCapability.getContactUri());
+ assertEquals(unparceledCapability.getSourceType(), testCapability.getSourceType());
+ assertEquals(unparceledCapability.getRequestResult(), testCapability.getRequestResult());
+ assertEquals(unparceledCapability.getCapabilityMechanism(),
+ testCapability.getCapabilityMechanism());
- RcsContactPresenceTuple unparceledTuple =
+ // Verify mmtel tuple
+ RcsContactPresenceTuple unparceledMMtelTuple =
unparceledCapability.getCapabilityTuple(RcsContactPresenceTuple.SERVICE_ID_MMTEL);
+ verifyUnparceledTuple(unparceledMMtelTuple, mmtelTuple);
- if (unparceledTuple != null) {
- unparceledTupleStatus = unparceledTuple.getStatus();
+ // Verify File transfer tuple
+ RcsContactPresenceTuple unparceledFtTuple =
+ unparceledCapability.getCapabilityTuple(RcsContactPresenceTuple.SERVICE_ID_FT);
+ verifyUnparceledTuple(unparceledFtTuple, ftTuple);
- ServiceCapabilities serviceCaps = unparceledTuple.getServiceCapabilities();
- if (serviceCaps != null) {
- unparceledVolteCapable = serviceCaps.isAudioCapable();
- unparceledVtCapable = serviceCaps.isVideoCapable();
- List<String> duplexModes = serviceCaps.getSupportedDuplexModes();
- if (duplexModes != null && !duplexModes.isEmpty()) {
- unparceledDuplexMode = duplexModes.get(0);
- }
+ // Verify all the tuples from the API getCapabilityTuples
+ List<RcsContactPresenceTuple> unparceledTuples = unparceledCapability.getCapabilityTuples();
+ assertNotNull(unparceledTuples);
+ assertEquals(2, unparceledTuples.size());
+ for (RcsContactPresenceTuple unparcelTuple : unparceledTuples) {
+ String serverId = unparcelTuple.getServiceId();
+ if (RcsContactPresenceTuple.SERVICE_ID_MMTEL.equals(serverId)) {
+ verifyUnparceledTuple(unparcelTuple, mmtelTuple);
+ } else if (RcsContactPresenceTuple.SERVICE_ID_FT.equals(serverId)) {
+ verifyUnparceledTuple(unparcelTuple, ftTuple);
+ } else {
+ fail("Invalid service ID: " + serverId);
}
}
+ }
- assertEquals(TEST_CONTACT, unparceledCapability.getContactUri());
- assertTrue(unparceledVolteCapable);
- assertTrue(unparceledVtCapable);
- assertEquals(RcsContactPresenceTuple.TUPLE_BASIC_STATUS_OPEN, unparceledTupleStatus);
- assertEquals(ServiceCapabilities.DUPLEX_MODE_FULL, unparceledDuplexMode);
- assertEquals(RcsContactPresenceTuple.SERVICE_ID_MMTEL, unparceledTuple.getServiceId());
- assertEquals(serviceVersion, unparceledTuple.getServiceVersion());
- assertEquals(serviceDescription, unparceledTuple.getServiceDescription());
+ private RcsContactPresenceTuple createPresenceMmtelTuple() {
+ ServiceCapabilities.Builder servCapsBuilder = new ServiceCapabilities.Builder(true, true);
+ servCapsBuilder.addSupportedDuplexMode(ServiceCapabilities.DUPLEX_MODE_FULL);
+
+ RcsContactPresenceTuple.Builder tupleBuilder = new RcsContactPresenceTuple.Builder(
+ RcsContactPresenceTuple.TUPLE_BASIC_STATUS_OPEN,
+ RcsContactPresenceTuple.SERVICE_ID_MMTEL, "1.0");
+ tupleBuilder.setContactUri(TEST_CONTACT)
+ .setTime(Instant.now())
+ .setServiceDescription("service description for contact 1")
+ .setServiceCapabilities(servCapsBuilder.build());
+ return tupleBuilder.build();
+ }
+
+ private RcsContactPresenceTuple createPresenceFtTuple() {
+ ServiceCapabilities.Builder servCapsBuilder = new ServiceCapabilities.Builder(true, true);
+ servCapsBuilder.addSupportedDuplexMode(ServiceCapabilities.DUPLEX_MODE_FULL);
+
+ RcsContactPresenceTuple.Builder tupleBuilder = new RcsContactPresenceTuple.Builder(
+ RcsContactPresenceTuple.TUPLE_BASIC_STATUS_OPEN,
+ RcsContactPresenceTuple.SERVICE_ID_FT, "1.0");
+ tupleBuilder.setContactUri(TEST_CONTACT)
+ .setServiceDescription("service description for contact2")
+ .setServiceCapabilities(servCapsBuilder.build());
+ return tupleBuilder.build();
+ }
+
+ private void verifyUnparceledTuple(RcsContactPresenceTuple unparceledTuple,
+ RcsContactPresenceTuple expectedTuple) {
+ assertNotNull(unparceledTuple);
+ assertEquals(unparceledTuple.getStatus(), expectedTuple.getStatus());
+ assertEquals(unparceledTuple.getServiceId(), expectedTuple.getServiceId());
+ assertEquals(unparceledTuple.getServiceDescription(),
+ expectedTuple.getServiceDescription());
+ assertEquals(unparceledTuple.getServiceVersion(), expectedTuple.getServiceVersion());
+ assertEquals(unparceledTuple.getContactUri(), expectedTuple.getContactUri());
+ assertEquals(unparceledTuple.getTime(), expectedTuple.getTime());
+
+ ServiceCapabilities unparceledServiceCaps = unparceledTuple.getServiceCapabilities();
+ ServiceCapabilities expectedServiceCaps = unparceledTuple.getServiceCapabilities();
+ assertNotNull(unparceledServiceCaps);
+ assertEquals(unparceledServiceCaps.isAudioCapable(), expectedServiceCaps.isAudioCapable());
+ assertEquals(unparceledServiceCaps.isVideoCapable(), expectedServiceCaps.isVideoCapable());
+
+ List<String> unparceledDuplexModes = unparceledServiceCaps.getSupportedDuplexModes();
+ List<String> expectedDuplexModes = expectedServiceCaps.getSupportedDuplexModes();
+ assertEquals(unparceledDuplexModes.size(), expectedDuplexModes.size());
+ assertTrue(unparceledDuplexModes.containsAll(expectedDuplexModes));
+
+ List<String> unparceledUnsupportedModes = unparceledServiceCaps.getUnsupportedDuplexModes();
+ List<String> expectedUnsupportedModes = expectedServiceCaps.getUnsupportedDuplexModes();
+ assertEquals(unparceledUnsupportedModes.size(), expectedUnsupportedModes.size());
+ assertTrue(unparceledUnsupportedModes.containsAll(expectedUnsupportedModes));
+ }
+
+ @Test
+ public void testParcelUnparcelForOptions() {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ final Set<String> featureTags = new HashSet<>();
+ featureTags.add(FEATURE_TAG_CHAT_IM);
+ featureTags.add(FEATURE_TAG_CHAT_SESSION);
+ featureTags.add(FEATURE_TAG_FILE_TRANSFER);
+
+ OptionsBuilder optionsBuilder = new OptionsBuilder(TEST_CONTACT,
+ RcsContactUceCapability.SOURCE_TYPE_CACHED);
+ optionsBuilder.addFeatureTags(featureTags);
+ optionsBuilder.addFeatureTag(FEATURE_TAG_POST_CALL);
+ optionsBuilder.setRequestResult(RcsContactUceCapability.REQUEST_RESULT_FOUND);
+
+ RcsContactUceCapability testCapability = optionsBuilder.build();
+
+ // parcel and unparcel
+ Parcel infoParceled = Parcel.obtain();
+ testCapability.writeToParcel(infoParceled, 0);
+ infoParceled.setDataPosition(0);
+ RcsContactUceCapability unparceledCapability =
+ RcsContactUceCapability.CREATOR.createFromParcel(infoParceled);
+ infoParceled.recycle();
+
+ assertEquals(unparceledCapability.getContactUri(), testCapability.getContactUri());
+ assertEquals(unparceledCapability.getSourceType(), testCapability.getSourceType());
+ assertEquals(unparceledCapability.getRequestResult(), testCapability.getRequestResult());
+ assertEquals(unparceledCapability.getCapabilityMechanism(),
+ testCapability.getCapabilityMechanism());
+
+ Set<String> expectedFeatureTags = new HashSet<>(featureTags);
+ expectedFeatureTags.add(FEATURE_TAG_POST_CALL);
+
+ Set<String> unparceledFeatureTags = unparceledCapability.getFeatureTags();
+ assertEquals(unparceledFeatureTags.size(), expectedFeatureTags.size());
+ Iterator<String> expectedFeatureTag = expectedFeatureTags.iterator();
+ while (expectedFeatureTag.hasNext()) {
+ assertTrue(unparceledFeatureTags.contains(expectedFeatureTag.next()));
+ }
}
}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
index 6307b2f..372301a 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
@@ -18,6 +18,8 @@
import static android.telephony.ims.RcsContactUceCapability.REQUEST_RESULT_FOUND;
import static android.telephony.ims.RcsContactUceCapability.REQUEST_RESULT_NOT_FOUND;
+import static android.telephony.ims.RcsContactUceCapability.SOURCE_TYPE_CACHED;
+import static android.telephony.ims.RcsContactUceCapability.SOURCE_TYPE_NETWORK;
import static android.telephony.ims.stub.RcsCapabilityExchangeImplBase.COMMAND_CODE_FETCH_ERROR;
import static android.telephony.ims.stub.RcsCapabilityExchangeImplBase.COMMAND_CODE_GENERIC_FAILURE;
import static android.telephony.ims.stub.RcsCapabilityExchangeImplBase.COMMAND_CODE_INSUFFICIENT_MEMORY;
@@ -65,6 +67,7 @@
import android.telephony.ims.stub.CapabilityExchangeEventListener;
import android.telephony.ims.stub.CapabilityExchangeEventListener.OptionsRequestCallback;
import android.telephony.ims.stub.ImsFeatureConfiguration;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
@@ -73,6 +76,7 @@
import com.android.compatibility.common.util.BlockedNumberUtil;
import com.android.compatibility.common.util.ShellIdentityUtils;
+import com.android.internal.os.SomeArgs;
import org.junit.After;
import org.junit.AfterClass;
@@ -82,16 +86,19 @@
import org.junit.runner.RunWith;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
+import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
@RunWith(AndroidJUnit4.class)
@@ -232,6 +239,8 @@
overrideCarrierConfig(null);
// Remove all the test contacts from EAB database
removeTestContactFromEab();
+
+ removeUceRequestDisallowedStatus();
}
@Test
@@ -314,7 +323,7 @@
ImsManager imsManager = getContext().getSystemService(ImsManager.class);
RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
assertNotNull("UCE adapter should not be null!", uceAdapter);
- ArrayList<Uri> numbers = new ArrayList<>(1);
+ Collection<Uri> numbers = new ArrayList<>(1);
numbers.add(sTestNumberUri);
// isUceSettingEnabled - read
@@ -368,14 +377,6 @@
}
}
- // Trigger carrier config changed
- PersistableBundle bundle = new PersistableBundle();
- bundle.putBoolean(CarrierConfigManager.Ims.KEY_ENABLE_PRESENCE_PUBLISH_BOOL, true);
- overrideCarrierConfig(bundle);
-
- // Connect to the TestImsService
- connectTestImsService();
-
// getUcePublishState without permission
try {
uceAdapter.getUcePublishState();
@@ -387,15 +388,12 @@
// getUcePublishState with permission
try {
ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(uceAdapter,
- (m) -> m.getUcePublishState(), ImsException.class,
+ RcsUceAdapter::getUcePublishState, ImsException.class,
"android.permission.READ_PRIVILEGED_PHONE_STATE");
} catch (SecurityException e) {
fail("getUcePublishState should succeed with READ_PRIVILEGED_PHONE_STATE.");
} catch (ImsException e) {
- // unsupported is a valid fail cause.
- if (e.getCode() != ImsException.CODE_ERROR_UNSUPPORTED_OPERATION) {
- fail("getUcePublishState failed with code " + e.getCode());
- }
+ // ImsExceptions are still valid because it means the permission check passed.
}
final RcsUceAdapter.OnPublishStateChangedListener publishStateListener = (state) -> { };
@@ -419,10 +417,7 @@
fail("addOnPublishStateChangedListener should succeed with "
+ "READ_PRIVILEGED_PHONE_STATE.");
} catch (ImsException e) {
- // unsupported is a valid fail cause.
- if (e.getCode() != ImsException.CODE_ERROR_UNSUPPORTED_OPERATION) {
- fail("addOnPublishStateChangedListener failed with code " + e.getCode());
- }
+ // ImsExceptions are still valid because it means the permission check passed.
}
// removeOnPublishStateChangedListener without permission
@@ -463,9 +458,6 @@
//expected
}
- // Lunch an activity to stay in the foreground.
- lunchUceActivity();
-
// requestCapabilities in the foreground
try {
ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(uceAdapter,
@@ -475,10 +467,7 @@
} catch (SecurityException e) {
fail("requestCapabilities should succeed with ACCESS_RCS_USER_CAPABILITY_EXCHANGE.");
} catch (ImsException e) {
- // unsupported is a valid fail cause.
- if (e.getCode() != ImsException.CODE_ERROR_UNSUPPORTED_OPERATION) {
- fail("requestCapabilities failed with code " + e.getCode());
- }
+ // ImsExceptions are still valid because it means the permission check passed.
}
// requestAvailability in the foreground
@@ -490,14 +479,9 @@
} catch (SecurityException e) {
fail("requestAvailability should succeed with ACCESS_RCS_USER_CAPABILITY_EXCHANGE.");
} catch (ImsException e) {
- // unsupported is a valid fail cause.
- if (e.getCode() != ImsException.CODE_ERROR_UNSUPPORTED_OPERATION) {
- fail("requestAvailability failed with code " + e.getCode());
- }
+ // ImsExceptions are still valid because it means the permission check passed.
}
- // Finish the activity
- finishUceActivity();
overrideCarrierConfig(null);
}
@@ -506,12 +490,18 @@
if (!ImsUtils.shouldTestImsService()) {
return;
}
+ // Start cap exchange disabled and enable later.
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putBoolean(CarrierConfigManager.Ims.KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL,
+ false);
+ overrideCarrierConfig(bundle);
+
ImsManager imsManager = getContext().getSystemService(ImsManager.class);
RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
assertNotNull("UCE adapter should not be null!", uceAdapter);
// Prepare the test contact and the callback
- ArrayList<Uri> numbers = new ArrayList<>(1);
+ Collection<Uri> numbers = new ArrayList<>(1);
numbers.add(sTestNumberUri);
ArrayList<String> pidfXmlList = new ArrayList<>(1);
@@ -552,16 +542,12 @@
}
// Trigger carrier config changed
- PersistableBundle bundle = new PersistableBundle();
bundle.putBoolean(CarrierConfigManager.Ims.KEY_ENABLE_PRESENCE_PUBLISH_BOOL, true);
overrideCarrierConfig(bundle);
// Connect to the TestImsService
connectTestImsService();
- // Stay in the foreground.
- lunchUceActivity();
-
TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
.getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
@@ -598,7 +584,7 @@
true);
overrideCarrierConfig(bundle);
- // Preapre the network response is 200 OK and the capabilities update
+ // Prepare the network response is 200 OK and the capabilities update
int networkRespCode = 200;
String networkRespReason = "OK";
capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
@@ -611,7 +597,9 @@
// Verify that the contact capability is received and the onCompleted is called.
RcsContactUceCapability capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, sTestNumberUri, REQUEST_RESULT_FOUND, true, true);
+ assertNotNull("Capabilities were not received for contact: " + sTestNumberUri, capability);
+ verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, true);
waitForResult(completeQueue);
errorQueue.clear();
@@ -623,10 +611,10 @@
// Verify that the contact capability is received and the onCompleted is called.
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, sTestNumberUri, REQUEST_RESULT_FOUND, true, true);
+ verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, true);
waitForResult(completeQueue);
- finishUceActivity();
overrideCarrierConfig(null);
}
@@ -642,10 +630,7 @@
// Connect to the TestImsService
setupTestImsService(uceAdapter, true, true, false);
- // Stay in the foreground
- lunchUceActivity();
-
- List<Uri> contacts = Collections.singletonList(sTestNumberUri);
+ Collection<Uri> contacts = Collections.singletonList(sTestNumberUri);
TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
.getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
@@ -708,14 +693,13 @@
assertEquals(expectedCallbackResult.intValue(), waitForIntResult(errorQueue));
assertEquals(0L, waitForLongResult(retryAfterQueue));
} catch (Exception e) {
- fail("requestCapabilities with command error failed: " + e);
+ fail("requestAvailability with command error failed: " + e);
} finally {
errorQueue.clear();
retryAfterQueue.clear();
}
});
- finishUceActivity();
overrideCarrierConfig(null);
}
@@ -731,7 +715,7 @@
// Connect to the ImsService
setupTestImsService(uceAdapter, true, true /* presence cap */, false /* options */);
- ArrayList<Uri> numbers = new ArrayList<>(1);
+ Collection<Uri> numbers = new ArrayList<>(1);
numbers.add(sTestNumberUri);
BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
@@ -815,9 +799,6 @@
}
}, RcsUceAdapter.ERROR_SERVER_UNAVAILABLE);
- // Stay in the foreground.
- lunchUceActivity();
-
TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
.getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
@@ -923,12 +904,11 @@
retryAfterQueue.clear();
}
- finishUceActivity();
overrideCarrierConfig(null);
}
@Test
- public void testRequestCapabilities() throws Exception {
+ public void testRequestCapabilitiesWithPresenceMechanism() throws Exception {
if (!ImsUtils.shouldTestImsService()) {
return;
}
@@ -945,10 +925,8 @@
TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
.getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
- ArrayList<Uri> numbers = new ArrayList<>(1);
- numbers.add(sTestNumberUri);
-
- BlockingQueue<Long> errorQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Long> errorRetryQueue = new LinkedBlockingQueue<>();
BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
@@ -962,8 +940,8 @@
}
@Override
public void onError(int errorCode, long retryAfterMilliseconds) {
- errorQueue.offer(new Long(errorCode));
- errorQueue.offer(retryAfterMilliseconds);
+ errorQueue.offer(errorCode);
+ errorRetryQueue.offer(retryAfterMilliseconds);
}
};
@@ -972,7 +950,7 @@
final Uri contact2 = sTestContact2Uri;
final Uri contact3 = sTestContact3Uri;
- ArrayList<Uri> contacts = new ArrayList<>(3);
+ Collection<Uri> contacts = new ArrayList<>(3);
contacts.add(contact1);
contacts.add(contact2);
contacts.add(contact3);
@@ -991,39 +969,73 @@
cb.onTerminated("", 0L);
});
- // Stay in the foreground.
- lunchUceActivity();
-
requestCapabilities(uceAdapter, contacts, callback);
// Verify that all the three contact's capabilities are received
RcsContactUceCapability capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact1, REQUEST_RESULT_FOUND, true, true);
+ assertNotNull("Capabilities were not received for contact: " + contact1, capability);
+ verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
+ true, true);
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact2, REQUEST_RESULT_FOUND, true, false);
+ assertNotNull("Capabilities were not received for contact: " + contact2, capability);
+ verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
+ true, false);
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact3, REQUEST_RESULT_FOUND, false, false);
+ assertNotNull("Capabilities were not received for contact: " + contact3, capability);
+ verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
+ false, false);
// Verify the onCompleted is called
waitForResult(completeQueue);
errorQueue.clear();
+ errorRetryQueue.clear();
completeQueue.clear();
capabilityQueue.clear();
removeTestContactFromEab();
// Setup the callback that some of the contacts are terminated.
capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ cb.onNetworkResponse(404, "NOT FOUND");
+ });
+
+ requestCapabilities(uceAdapter, contacts, callback);
+
+ // Verify the contacts are not found.
+ capability = waitForResult(capabilityQueue);
+ verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
+ false, false);
+
+ capability = waitForResult(capabilityQueue);
+ verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
+ false, false);
+
+ capability = waitForResult(capabilityQueue);
+ verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
+ false, false);
+
+ int errorCode = waitForResult(errorQueue);
+ assertEquals(RcsUceAdapter.ERROR_NOT_FOUND, errorCode);
+
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+ removeTestContactFromEab();
+
+ // Setup the callback that some of the contacts are terminated.
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ List<Uri> uriList = new ArrayList(uris);
cb.onNetworkResponse(networkRespCode, networkRespReason);
// Notify capabilities updated for the first contact
String pidfXml = pidfXmlList.get(0);
cb.onNotifyCapabilitiesUpdate(Collections.singletonList(pidfXml));
List<Pair<Uri, String>> terminatedResources = new ArrayList<>();
- for (int i = 1; i < uris.size(); i++) {
- Pair<Uri, String> pair = Pair.create(uris.get(i), "noresource");
+ for (int i = 1; i < uriList.size(); i++) {
+ Pair<Uri, String> pair = Pair.create(uriList.get(i), "noresource");
terminatedResources.add(pair);
}
cb.onResourceTerminated(terminatedResources);
@@ -1034,19 +1046,301 @@
// Verify the first contact is found.
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact1, REQUEST_RESULT_FOUND, true, true);
+ verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
+ true, true);
// Verify the reset contacts are not found.
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact2, REQUEST_RESULT_NOT_FOUND, true, false);
+ verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
+ true, false);
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact3, REQUEST_RESULT_NOT_FOUND, false, false);
+ verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
+ false, false);
// Verify the onCompleted is called
waitForResult(completeQueue);
- finishUceActivity();
+ overrideCarrierConfig(null);
+ }
+
+ @Test
+ public void testRequestCapabilitiesFromCacheWithPresenceMechanism() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+ RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+ assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+ // Remove the test contact capabilities
+ removeTestContactFromEab();
+
+ // Connect to the ImsService
+ setupTestImsService(uceAdapter, true, true /* presence cap */, false /* OPTIONS */);
+
+ TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+ .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+ BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Long> errorRetryQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
+ RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+ @Override
+ public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+ capabilities.forEach(c -> capabilityQueue.offer(c));
+ }
+ @Override
+ public void onComplete() {
+ completeQueue.offer(true);
+ }
+ @Override
+ public void onError(int errorCode, long retryAfterMilliseconds) {
+ errorQueue.offer(errorCode);
+ errorRetryQueue.offer(retryAfterMilliseconds);
+ }
+ };
+
+ // Prepare three contacts
+ final Uri contact1 = sTestNumberUri;
+ final Uri contact2 = sTestContact2Uri;
+ final Uri contact3 = sTestContact3Uri;
+
+ Collection<Uri> contacts = new ArrayList<>(3);
+ contacts.add(contact1);
+ contacts.add(contact2);
+ contacts.add(contact3);
+
+ ArrayList<String> pidfXmlList = new ArrayList<>(3);
+ pidfXmlList.add(getPidfXmlData(contact1, true, true));
+ pidfXmlList.add(getPidfXmlData(contact2, true, false));
+ pidfXmlList.add(getPidfXmlData(contact3, false, false));
+
+ // Setup the network response is 200 OK and notify capabilities update
+ int networkRespCode = 200;
+ String networkRespReason = "OK";
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ cb.onNetworkResponse(networkRespCode, networkRespReason);
+ cb.onNotifyCapabilitiesUpdate(pidfXmlList);
+ cb.onTerminated("", 0L);
+ });
+
+ requestCapabilities(uceAdapter, contacts, callback);
+
+ // Verify that all the three contact's capabilities are received
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received for contact: " + contact1, capability);
+ verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
+ true, true);
+
+ capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received for contact: " + contact2, capability);
+ verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
+ true, false);
+
+ capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received for contact: " + contact3, capability);
+ verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
+ false, false);
+
+ // Verify the onCompleted is called
+ waitForResult(completeQueue);
+
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+
+ // The request should not be called because the capabilities should be retrieved from cache.
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ fail("The request should not be called.");
+ });
+
+ requestCapabilities(uceAdapter, contacts, callback);
+
+ // Verify that all the three contact's capabilities are received
+ capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received for contact: " + contact1, capability);
+ verifyCapabilityResult(capability, contact1, SOURCE_TYPE_CACHED, REQUEST_RESULT_FOUND,
+ true, true);
+
+ capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received for contact: " + contact2, capability);
+ verifyCapabilityResult(capability, contact2, SOURCE_TYPE_CACHED, REQUEST_RESULT_FOUND,
+ true, false);
+
+ capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received for contact: " + contact3, capability);
+ verifyCapabilityResult(capability, contact3, SOURCE_TYPE_CACHED, REQUEST_RESULT_FOUND,
+ false, false);
+
+ // Verify the onCompleted is called
+ waitForResult(completeQueue);
+
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+ removeTestContactFromEab();
+
+ overrideCarrierConfig(null);
+ }
+
+ @Test
+ public void testIndividualRequestCapabilities() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+ RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+ assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+ // Remove the test contact capabilities
+ removeTestContactFromEab();
+
+ // Override the carrier config to not support group subscribe.
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putBoolean(CarrierConfigManager.Ims.KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL, false);
+ overrideCarrierConfig(bundle);
+
+ // Connect to the ImsService
+ setupTestImsService(uceAdapter, true, true /* presence cap */, false /* OPTIONS */);
+
+ TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+ .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+ BlockingQueue<Long> errorQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+ List<RcsContactUceCapability> capabilityQueue = new ArrayList<>();
+ RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+ @Override
+ public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+ capabilities.forEach(c -> capabilityQueue.add(c));
+ }
+ @Override
+ public void onComplete() {
+ completeQueue.offer(true);
+ }
+ @Override
+ public void onError(int errorCode, long retryAfterMilliseconds) {
+ errorQueue.offer(new Long(errorCode));
+ errorQueue.offer(retryAfterMilliseconds);
+ }
+ };
+
+ // Prepare three contacts
+ final Uri contact1 = sTestNumberUri;
+ final Uri contact2 = sTestContact2Uri;
+ final Uri contact3 = sTestContact3Uri;
+
+ Collection<Uri> contacts = new ArrayList<>(3);
+ contacts.add(contact1);
+ contacts.add(contact2);
+ contacts.add(contact3);
+
+ List<String> pidfXml1 = Collections.singletonList(getPidfXmlData(contact1, true, true));
+ List<String> pidfXml2 = Collections.singletonList(getPidfXmlData(contact2, true, false));
+ List<String> pidfXml3 = Collections.singletonList(getPidfXmlData(contact3, false, false));
+
+ // Setup the network response is 200 OK and notify capabilities update
+ int networkRespCode = 200;
+ String networkRespReason = "OK";
+ AtomicInteger receiveRequestCount = new AtomicInteger(0);
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ receiveRequestCount.incrementAndGet();
+ cb.onNetworkResponse(networkRespCode, networkRespReason);
+ assertEquals(1, uris.size());
+ String uriPart = uris.iterator().next().getSchemeSpecificPart();
+ if (contact1.getSchemeSpecificPart().equalsIgnoreCase(uriPart)) {
+ cb.onNotifyCapabilitiesUpdate(pidfXml1);
+ } else if (contact2.getSchemeSpecificPart().equalsIgnoreCase(uriPart)) {
+ cb.onNotifyCapabilitiesUpdate(pidfXml2);
+ } else if (contact3.getSchemeSpecificPart().equalsIgnoreCase(uriPart)) {
+ cb.onNotifyCapabilitiesUpdate(pidfXml3);
+ }
+ cb.onTerminated("", 0L);
+ });
+
+ requestCapabilities(uceAdapter, contacts, callback);
+
+ // Verify the onCompleted is called
+ waitForResult(completeQueue);
+
+ // Verify the capability request has been split to individual requests.
+ assertEquals(contacts.size(), receiveRequestCount.get());
+
+ // verify the capabilities result
+ assertEquals(contacts.size(), capabilityQueue.size());
+ for (RcsContactUceCapability capability : capabilityQueue) {
+ Uri contact = capability.getContactUri();
+ if (contact1.equals(contact)) {
+ verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, true);
+ } else if (contact2.equals(contact)) {
+ verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, false);
+ } else if (contact3.equals(contact)) {
+ verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, false, false);
+ } else {
+ fail("The contact of the capabilities result is invalid.");
+ }
+ }
+
+ errorQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+ removeTestContactFromEab();
+ receiveRequestCount.set(0);
+
+ // Setup the callback that some of the contacts are terminated.
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ receiveRequestCount.incrementAndGet();
+ cb.onNetworkResponse(networkRespCode, networkRespReason);
+ assertEquals(1, uris.size());
+ String uriPart = uris.iterator().next().getSchemeSpecificPart();
+ if (contact1.getSchemeSpecificPart().equalsIgnoreCase(uriPart)) {
+ cb.onNotifyCapabilitiesUpdate(pidfXml1);
+ } else {
+ // Notify resources terminated for the reset contacts
+ List<Uri> uriList = new ArrayList(uris);
+ List<Pair<Uri, String>> terminatedResources = new ArrayList<>();
+ for (int i = 0; i < uriList.size(); i++) {
+ Pair<Uri, String> pair = Pair.create(uriList.get(i), "noresource");
+ terminatedResources.add(pair);
+ }
+ cb.onResourceTerminated(terminatedResources);
+ }
+ cb.onTerminated("", 0L);
+ });
+
+ requestCapabilities(uceAdapter, contacts, callback);
+
+ // Verify the onCompleted is called
+ waitForResult(completeQueue);
+
+ // Verify the capability request has been split to individual requests.
+ assertEquals(contacts.size(), receiveRequestCount.get());
+
+ // verify the capabilities result
+ assertEquals(contacts.size(), capabilityQueue.size());
+ for (RcsContactUceCapability capability : capabilityQueue) {
+ Uri contact = capability.getContactUri();
+ if (contact1.equals(contact)) {
+ verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, true);
+ } else if (contact2.equals(contact)) {
+ verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, true, false);
+ } else if (contact3.equals(contact)) {
+ verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false,
+ false);
+ } else {
+ fail("The contact of the capabilities result is invalid.");
+ }
+ }
overrideCarrierConfig(null);
}
@@ -1069,7 +1363,7 @@
.getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
// The test contact
- ArrayList<Uri> contacts = new ArrayList<>(3);
+ Collection<Uri> contacts = new ArrayList<>(3);
contacts.add(sTestNumberUri);
// The result callback
@@ -1105,29 +1399,19 @@
});
// Request capabilities by calling the API requestCapabilities.
- try {
- ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(
- uceAdapter,
- adapter -> adapter.requestCapabilities(contacts, Runnable::run, callback),
- ImsException.class,
- "android.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE");
- } catch (SecurityException e) {
- fail("requestCapabilities should succeed with ACCESS_RCS_USER_CAPABILITY_EXCHANGE.");
- } catch (ImsException e) {
- fail("requestCapabilities failed " + e);
- }
+ requestCapabilities(uceAdapter, contacts, callback);
// Verify the callback "onCapabilitiesReceived" is called.
RcsContactUceCapability capability = waitForResult(capabilityQueue);
- // Verify the callback "onComplete" is called.
- waitForResult(completeQueue);
assertNotNull("RcsContactUceCapability should not be null", capability);
+ // Verify the callback "onComplete" is called.
+ assertNotNull(waitForResult(completeQueue));
assertEquals(RcsContactUceCapability.SOURCE_TYPE_NETWORK, capability.getSourceType());
assertEquals(sTestNumberUri, capability.getContactUri());
assertEquals(RcsContactUceCapability.REQUEST_RESULT_FOUND, capability.getRequestResult());
assertEquals(RcsContactUceCapability.CAPABILITY_MECHANISM_OPTIONS,
capability.getCapabilityMechanism());
- List<String> resultFeatureTags = capability.getOptionsFeatureTags();
+ Set<String> resultFeatureTags = capability.getFeatureTags();
assertEquals(featureTags.size(), resultFeatureTags.size());
for (String featureTag : featureTags) {
if (!resultFeatureTags.contains(featureTag)) {
@@ -1141,18 +1425,7 @@
removeTestContactFromEab();
// Request capabilities by calling the API requestAvailability.
- try {
- ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(
- uceAdapter,
- adapter -> adapter.requestAvailability(sTestContact2Uri,
- Runnable::run, callback),
- ImsException.class,
- "android.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE");
- } catch (SecurityException e) {
- fail("requestCapabilities should succeed with ACCESS_RCS_USER_CAPABILITY_EXCHANGE.");
- } catch (ImsException e) {
- fail("requestCapabilities failed " + e);
- }
+ requestAvailability(uceAdapter, sTestContact2Uri, callback);
// Verify the callback "onCapabilitiesReceived" is called.
capability = waitForResult(capabilityQueue);
@@ -1164,7 +1437,7 @@
assertEquals(RcsContactUceCapability.REQUEST_RESULT_FOUND, capability.getRequestResult());
assertEquals(RcsContactUceCapability.CAPABILITY_MECHANISM_OPTIONS,
capability.getCapabilityMechanism());
- resultFeatureTags = capability.getOptionsFeatureTags();
+ resultFeatureTags = capability.getFeatureTags();
assertEquals(featureTags.size(), resultFeatureTags.size());
for (String featureTag : featureTags) {
if (!resultFeatureTags.contains(featureTag)) {
@@ -1185,25 +1458,261 @@
});
// Request capabilities by calling the API requestCapabilities.
- try {
- ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(
- uceAdapter,
- adapter -> adapter.requestCapabilities(contacts, Runnable::run, callback),
- ImsException.class,
- "android.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE");
- } catch (SecurityException e) {
- fail("requestCapabilities should succeed with ACCESS_RCS_USER_CAPABILITY_EXCHANGE.");
- } catch (ImsException e) {
- fail("requestCapabilities failed " + e);
- }
+ requestCapabilities(uceAdapter, contacts, callback);
// Verify the callback "onError" is called.
assertEquals(RcsUceAdapter.ERROR_GENERIC_FAILURE, waitForLongResult(errorQueue));
- // The callback "onCapabilitiesReceived" should not be called.
- if (capabilityQueue.poll() != null) {
- fail("onCapabilitiesReceived should not be called.");
+ // The callback "onCapabilitiesReceived" should be called with NOT FOUND
+ capability = waitForResult(capabilityQueue);
+ assertEquals(RcsContactUceCapability.REQUEST_RESULT_NOT_FOUND,
+ capability.getRequestResult());
+
+ overrideCarrierConfig(null);
+ }
+
+ @Test
+ public void testRequestCapabilitiesFromCacheWithOptionsMechanism() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
}
+ ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+ RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+ assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+ // Remove the test contact capabilities
+ removeTestContactFromEab();
+
+ // Connect to the ImsService
+ setupTestImsService(uceAdapter, true, false, true /* OPTIONS enabled */);
+
+ TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+ .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+ // The result callback
+ BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Long> retryAfterQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
+ RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+ @Override
+ public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+ capabilities.forEach(c -> capabilityQueue.offer(c));
+ }
+ @Override
+ public void onComplete() {
+ completeQueue.offer(true);
+ }
+ @Override
+ public void onError(int errorCode, long retryAfterMilliseconds) {
+ errorQueue.offer(errorCode);
+ retryAfterQueue.offer(retryAfterMilliseconds);
+ }
+ };
+
+ // Set the result of the network response is 200 OK.
+ final List<String> featureTags = new ArrayList<>();
+ featureTags.add(FEATURE_TAG_CHAT);
+ featureTags.add(FEATURE_TAG_FILE_TRANSFER);
+ featureTags.add(FEATURE_TAG_MMTEL_AUDIO_CALL);
+ featureTags.add(FEATURE_TAG_MMTEL_VIDEO_CALL);
+ capabilityExchangeImpl.setOptionsOperation((contact, myCapabilities, optionsCallback) -> {
+ int sipCode = 200;
+ String reason = "OK";
+ optionsCallback.onNetworkResponse(sipCode, reason, featureTags);
+ });
+
+ // Request capabilities with the for the first time.
+ requestCapabilities(uceAdapter, Collections.singletonList(sTestNumberUri), callback);
+
+ // Verify the callback "onCapabilitiesReceived" is called.
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("RcsContactUceCapability should not be null", capability);
+ // Verify the callback "onComplete" is called.
+ assertNotNull(waitForResult(completeQueue));
+ assertEquals(RcsContactUceCapability.SOURCE_TYPE_NETWORK, capability.getSourceType());
+ assertEquals(sTestNumberUri, capability.getContactUri());
+ assertEquals(RcsContactUceCapability.REQUEST_RESULT_FOUND, capability.getRequestResult());
+ assertEquals(RcsContactUceCapability.CAPABILITY_MECHANISM_OPTIONS,
+ capability.getCapabilityMechanism());
+ Set<String> resultFeatureTags = capability.getFeatureTags();
+ assertEquals(featureTags.size(), resultFeatureTags.size());
+ for (String featureTag : featureTags) {
+ if (!resultFeatureTags.contains(featureTag)) {
+ fail("Cannot find feature tag in the result");
+ }
+ }
+ errorQueue.clear();
+ retryAfterQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+
+ // Request capabilities for the second time.
+ requestAvailability(uceAdapter, sTestContact2Uri, callback);
+
+ // Verify the callback "onCapabilitiesReceived" is called.
+ capability = waitForResult(capabilityQueue);
+ // Verify the callback "onComplete" is called.
+ waitForResult(completeQueue);
+ assertNotNull("RcsContactUceCapability should not be null", capability);
+ assertEquals(RcsContactUceCapability.SOURCE_TYPE_NETWORK, capability.getSourceType());
+ assertEquals(sTestContact2Uri, capability.getContactUri());
+ assertEquals(RcsContactUceCapability.REQUEST_RESULT_FOUND, capability.getRequestResult());
+ assertEquals(RcsContactUceCapability.CAPABILITY_MECHANISM_OPTIONS,
+ capability.getCapabilityMechanism());
+ resultFeatureTags = capability.getFeatureTags();
+ assertEquals(featureTags.size(), resultFeatureTags.size());
+ for (String featureTag : featureTags) {
+ if (!resultFeatureTags.contains(featureTag)) {
+ fail("Cannot find feature tag in the result");
+ }
+ }
+ errorQueue.clear();
+ retryAfterQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+
+ // Set the OPTIONS result is failed because the capabilities should be retrieved from cache.
+ capabilityExchangeImpl.setOptionsOperation((contact, myCapabilities, optionsCallback) -> {
+ fail("The Options request should not be called.");
+ });
+
+ // The contact to requeste the capabilities is the same as the first time.
+ requestCapabilities(uceAdapter, Collections.singletonList(sTestNumberUri), callback);
+
+ // Verify the callback "onCapabilitiesReceived" is called.
+ capability = waitForResult(capabilityQueue);
+ assertNotNull("RcsContactUceCapability should not be null", capability);
+ // Verify the callback "onComplete" is called.
+ assertNotNull(waitForResult(completeQueue));
+ // Verify the capabilities are retrieved from the cache.
+ assertEquals(RcsContactUceCapability.SOURCE_TYPE_CACHED, capability.getSourceType());
+ assertEquals(sTestNumberUri, capability.getContactUri());
+ assertEquals(RcsContactUceCapability.REQUEST_RESULT_FOUND, capability.getRequestResult());
+ assertEquals(RcsContactUceCapability.CAPABILITY_MECHANISM_OPTIONS,
+ capability.getCapabilityMechanism());
+ resultFeatureTags = capability.getFeatureTags();
+ assertEquals(featureTags.size(), resultFeatureTags.size());
+ for (String featureTag : featureTags) {
+ if (!resultFeatureTags.contains(featureTag)) {
+ fail("Cannot find feature tag in the result");
+ }
+ }
+ errorQueue.clear();
+ retryAfterQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+ removeTestContactFromEab();
+
+ overrideCarrierConfig(null);
+ }
+
+ @Test
+ public void testIndividualRequestCapabilitiesWithOptionsMechanism() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+ RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+ assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+ // Remove the test contact capabilities
+ removeTestContactFromEab();
+
+ // Connect to the ImsService
+ setupTestImsService(uceAdapter, true, false, true /* OPTIONS enabled */);
+
+ TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+ .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+ // Prepare three test contacts
+ Collection<Uri> contacts = new ArrayList<>(3);
+ contacts.add(sTestNumberUri);
+ contacts.add(sTestContact2Uri);
+ contacts.add(sTestContact3Uri);
+
+ // The result callback
+ BlockingQueue<Long> errorQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+ List<RcsContactUceCapability> capabilityQueue = new ArrayList<>();
+ RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+ @Override
+ public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+ capabilities.forEach(c -> capabilityQueue.add(c));
+ }
+ @Override
+ public void onComplete() {
+ completeQueue.offer(true);
+ }
+ @Override
+ public void onError(int errorCode, long retryAfterMilliseconds) {
+ errorQueue.offer(new Long(errorCode));
+ errorQueue.offer(retryAfterMilliseconds);
+ }
+ };
+
+ // Set the result of the network response is 200 OK.
+ final List<String> featureTags = new ArrayList<>();
+ featureTags.add(FEATURE_TAG_CHAT);
+ featureTags.add(FEATURE_TAG_FILE_TRANSFER);
+ featureTags.add(FEATURE_TAG_MMTEL_AUDIO_CALL);
+ featureTags.add(FEATURE_TAG_MMTEL_VIDEO_CALL);
+
+ AtomicInteger receiveRequestCount = new AtomicInteger(0);
+
+ capabilityExchangeImpl.setOptionsOperation((contact, myCapabilities, optionsCallback) -> {
+ receiveRequestCount.incrementAndGet();
+ int sipCode = 200;
+ String reason = "OK";
+ optionsCallback.onNetworkResponse(sipCode, reason, featureTags);
+ });
+
+ // Request capabilities by calling the API requestCapabilities.
+ requestCapabilities(uceAdapter, contacts, callback);
+
+ // Verify the callback "onComplete" is called.
+ assertNotNull(waitForResult(completeQueue));
+
+ // Verify the capability request has been split to individual requests.
+ assertEquals(contacts.size(), receiveRequestCount.get());
+
+ // Verify the result
+ verifyOptionsCapabilityResult(capabilityQueue, contacts,
+ RcsContactUceCapability.SOURCE_TYPE_NETWORK,
+ RcsContactUceCapability.CAPABILITY_MECHANISM_OPTIONS,
+ RcsContactUceCapability.REQUEST_RESULT_FOUND, featureTags);
+
+ errorQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+ receiveRequestCount.set(0);
+ removeTestContactFromEab();
+
+ // Set the OPTIONS result is failed.
+ capabilityExchangeImpl.setOptionsOperation((contact, myCapabilities, optionsCallback) -> {
+ receiveRequestCount.incrementAndGet();
+ int sipCode = 400;
+ String reason = "Bad Request";
+ optionsCallback.onNetworkResponse(sipCode, reason, Collections.EMPTY_LIST);
+ });
+
+ // Request capabilities by calling the API requestCapabilities.
+ requestCapabilities(uceAdapter, contacts, callback);
+
+ // Verify the callback "onError" is called.
+ assertEquals(RcsUceAdapter.ERROR_GENERIC_FAILURE, waitForLongResult(errorQueue));
+
+ // Verify the result
+ verifyOptionsCapabilityResult(capabilityQueue, contacts,
+ RcsContactUceCapability.SOURCE_TYPE_NETWORK,
+ RcsContactUceCapability.CAPABILITY_MECHANISM_OPTIONS,
+ RcsContactUceCapability.REQUEST_RESULT_NOT_FOUND, Collections.EMPTY_LIST);
+
+ errorQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+ receiveRequestCount.set(0);
+ removeTestContactFromEab();
overrideCarrierConfig(null);
}
@@ -1227,7 +1736,7 @@
sServiceConnector.getCarrierService().getRcsFeature().getEventListener();
final Uri contact = sTestContact2Uri;
- List<String> remoteCapabilities = new ArrayList<>();
+ Set<String> remoteCapabilities = new ArraySet<>();
remoteCapabilities.add(FEATURE_TAG_CHAT);
remoteCapabilities.add(FEATURE_TAG_FILE_TRANSFER);
remoteCapabilities.add(FEATURE_TAG_MMTEL_AUDIO_CALL);
@@ -1251,7 +1760,7 @@
// Verify receive the result
Pair<RcsContactUceCapability, Boolean> capability = waitForResult(respToCapRequestQueue);
assertNotNull("RcsContactUceCapability should not be null", capability);
- assertEquals(RcsContactUceCapability.SOURCE_TYPE_NETWORK, capability.first.getSourceType());
+ assertEquals(RcsContactUceCapability.SOURCE_TYPE_CACHED, capability.first.getSourceType());
assertEquals(RcsContactUceCapability.REQUEST_RESULT_FOUND,
capability.first.getRequestResult());
assertEquals(RcsContactUceCapability.CAPABILITY_MECHANISM_OPTIONS,
@@ -1282,7 +1791,7 @@
sServiceConnector.getCarrierService().getRcsFeature().getEventListener();
final Uri contact = sTestNumberUri;
- List<String> remoteCapabilities = new ArrayList<>();
+ Set<String> remoteCapabilities = new ArraySet<>();
remoteCapabilities.add(FEATURE_TAG_CHAT);
remoteCapabilities.add(FEATURE_TAG_FILE_TRANSFER);
remoteCapabilities.add(FEATURE_TAG_MMTEL_AUDIO_CALL);
@@ -1313,7 +1822,7 @@
Pair<RcsContactUceCapability, Boolean> capability =
waitForResult(respToCapRequestQueue);
assertNotNull("RcsContactUceCapability should not be null", capability);
- assertEquals(RcsContactUceCapability.SOURCE_TYPE_NETWORK,
+ assertEquals(RcsContactUceCapability.SOURCE_TYPE_CACHED,
capability.first.getSourceType());
assertEquals(RcsContactUceCapability.REQUEST_RESULT_FOUND,
capability.first.getRequestResult());
@@ -1330,6 +1839,501 @@
overrideCarrierConfig(null);
}
+ @Test
+ public void testForbidCapabilitiesRequest() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+ RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+ assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+ // Remove the test contact capabilities
+ removeTestContactFromEab();
+
+ // Override the carrier config of SIP 489 request forbidden.
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putBoolean(CarrierConfigManager.Ims.KEY_RCS_REQUEST_FORBIDDEN_BY_SIP_489_BOOL, true);
+ overrideCarrierConfig(bundle);
+
+ // Connect to the ImsService
+ setupTestImsService(uceAdapter, true, true /* presence cap */, false /* OPTIONS */);
+
+ TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+ .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+ BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Long> retryAfterQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+ List<RcsContactUceCapability> capabilityQueue = new ArrayList<>();
+ RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+ @Override
+ public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+ capabilities.forEach(c -> capabilityQueue.add(c));
+ }
+
+ @Override
+ public void onComplete() {
+ completeQueue.offer(true);
+ }
+
+ @Override
+ public void onError(int errorCode, long retryAfterMillis) {
+ errorQueue.offer(errorCode);
+ retryAfterQueue.offer(retryAfterMillis);
+ }
+ };
+
+ // Prepare two contacts
+ final Uri contact1 = sTestNumberUri;
+ final Uri contact2 = sTestContact2Uri;
+ Collection<Uri> contacts = new ArrayList<>(2);
+ contacts.add(contact1);
+ contacts.add(contact2);
+
+ // Prepare the network response.
+ final int sipCodeBadEvent = 489;
+ final int sipCodeForbidden = 403;
+ AtomicInteger subscribeRequestCount = new AtomicInteger(0);
+
+ // Prepare a map to define the sip code and its associated result.
+ Map<Integer, Integer> networkSipCodeMap = new HashMap<>();
+ networkSipCodeMap.put(sipCodeBadEvent, RcsUceAdapter.ERROR_FORBIDDEN);
+ networkSipCodeMap.put(sipCodeForbidden, RcsUceAdapter.ERROR_FORBIDDEN);
+
+ // Verify each command error code and the expected callback result
+ networkSipCodeMap.forEach((sipCode, expectedCallbackResult) -> {
+ // Setup the capabilities request response with the given sip code.
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ subscribeRequestCount.incrementAndGet();
+ cb.onNetworkResponse(sipCode, "");
+ });
+
+ try {
+ // Request contact uce capabilities
+ requestCapabilities(uceAdapter, contacts, callback);
+
+ // Verify that the callback "onError" is called with the error code FORBIDDEN
+ assertEquals(RcsUceAdapter.ERROR_FORBIDDEN, waitForIntResult(errorQueue));
+ // Verify the retryAfter value
+ long retryAfterMillis = waitForLongResult(retryAfterQueue);
+ if (sipCode == sipCodeForbidden) {
+ assertEquals(0L, retryAfterMillis);
+ } else if (sipCode == sipCodeBadEvent) {
+ assertTrue(retryAfterMillis > 0L);
+ }
+
+ // Verify the ImsService received the capabilities request.
+ assertEquals(1, subscribeRequestCount.get());
+ } catch (Exception e) {
+ fail("testForbiddenResponseToCapabilitiesRequest with command error failed: " + e);
+ } finally {
+ errorQueue.clear();
+ retryAfterQueue.clear();
+ subscribeRequestCount.set(0);
+ }
+
+ // Prepare the network response with sip code 200 OK
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ subscribeRequestCount.incrementAndGet();
+ cb.onNetworkResponse(200, "OK");
+ });
+
+ try {
+ // Request contact uce capabilities again.
+ requestCapabilities(uceAdapter, contacts, callback);
+
+ // Verify that the callback "onError" is called with the error code FORBIDDEN
+ assertEquals(RcsUceAdapter.ERROR_FORBIDDEN, waitForIntResult(errorQueue));
+ // Verify the retryAfter value
+ long retryAfterMillis = waitForLongResult(retryAfterQueue);
+ if (sipCode == sipCodeForbidden) {
+ assertEquals(0L, retryAfterMillis);
+ } else if (sipCode == sipCodeBadEvent) {
+ assertTrue(retryAfterMillis > 0L);
+ }
+
+ // Verify that the capabilities won't be send to the ImsService because the
+ // uce request is forbidden.
+ assertEquals(0, subscribeRequestCount.get());
+ } catch (Exception e) {
+ fail("testForbiddenResponseToCapabilitiesRequest with command error failed: " + e);
+ } finally {
+ errorQueue.clear();
+ retryAfterQueue.clear();
+ subscribeRequestCount.set(0);
+ }
+
+ // Reset the device status
+ removeUceRequestDisallowedStatus();
+ });
+
+ overrideCarrierConfig(null);
+ }
+
+ @Test
+ public void testTerminatedCallbackWithCapabilitiesRequest() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+ RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+ assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+ // Remove the test contact capabilities
+ removeTestContactFromEab();
+
+ // Connect to the ImsService
+ setupTestImsService(uceAdapter, true, true /* presence cap */, false /* OPTIONS */);
+
+ ArrayList<String> pidfXmlList = new ArrayList<>(1);
+ pidfXmlList.add(getPidfXmlData(sTestNumberUri, true, true));
+
+ TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+ .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+ BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Long> errorRetryQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
+ RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+ @Override
+ public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+ capabilities.forEach(c -> capabilityQueue.offer(c));
+ }
+ @Override
+ public void onComplete() {
+ completeQueue.offer(true);
+ }
+ @Override
+ public void onError(int errorCode, long retryAfterMillis) {
+ errorQueue.offer(errorCode);
+ errorRetryQueue.offer(retryAfterMillis);
+ }
+ };
+
+ // Prepare the test contact and the callback
+ Collection<Uri> numbers = new ArrayList<>(1);
+ numbers.add(sTestNumberUri);
+
+ // Prepare the network response is 200 OK and the capabilities update
+ int networkRespCode = 200;
+ String networkRespReason = "OK";
+
+ Map<SomeArgs, SomeArgs> terminatedMap = new HashMap<>();
+ SomeArgs deactivatedArgs = SomeArgs.obtain();
+ deactivatedArgs.arg1 = "deactivated";
+ deactivatedArgs.arg2 = Long.valueOf(3000L);
+ SomeArgs deactivatedExpectedArgs = SomeArgs.obtain();
+ deactivatedExpectedArgs.argi1 = RcsUceAdapter.ERROR_GENERIC_FAILURE;
+ deactivatedExpectedArgs.arg1 = Long.valueOf(3000L);
+ terminatedMap.put(deactivatedArgs, deactivatedExpectedArgs);
+
+ SomeArgs probationArgs = SomeArgs.obtain();
+ probationArgs.arg1 = "probation";
+ probationArgs.arg2 = Long.valueOf(4000L);
+ SomeArgs probationExpectedArgs = SomeArgs.obtain();
+ probationExpectedArgs.argi1 = RcsUceAdapter.ERROR_GENERIC_FAILURE;
+ probationExpectedArgs.arg1 = Long.valueOf(4000L);
+ terminatedMap.put(probationArgs, probationExpectedArgs);
+
+ SomeArgs rejectedArgs = SomeArgs.obtain();
+ rejectedArgs.arg1 = "rejected";
+ rejectedArgs.arg2 = Long.valueOf(5000L);
+ SomeArgs rejectedExpectedArgs = SomeArgs.obtain();
+ rejectedExpectedArgs.argi1 = RcsUceAdapter.ERROR_NOT_AUTHORIZED;
+ rejectedExpectedArgs.arg1 = Long.valueOf(0L);
+ terminatedMap.put(rejectedArgs, rejectedExpectedArgs);
+
+ SomeArgs timeoutArgs = SomeArgs.obtain();
+ timeoutArgs.arg1 = "timeout";
+ timeoutArgs.arg2 = Long.valueOf(6000L);
+ SomeArgs timeoutExpectedArgs = SomeArgs.obtain();
+ timeoutExpectedArgs.argi1 = RcsUceAdapter.ERROR_REQUEST_TIMEOUT;
+ timeoutExpectedArgs.arg1 = Long.valueOf(6000L);
+ terminatedMap.put(timeoutArgs, timeoutExpectedArgs);
+
+ SomeArgs giveupArgs = SomeArgs.obtain();
+ giveupArgs.arg1 = "giveup";
+ giveupArgs.arg2 = Long.valueOf(7000L);
+ SomeArgs giveupExpectedArgs = SomeArgs.obtain();
+ giveupExpectedArgs.argi1 = RcsUceAdapter.ERROR_NOT_AUTHORIZED;
+ giveupExpectedArgs.arg1 = Long.valueOf(7000L);
+ terminatedMap.put(giveupArgs, giveupExpectedArgs);
+
+ SomeArgs noresourceArgs = SomeArgs.obtain();
+ noresourceArgs.arg1 = "noresource";
+ noresourceArgs.arg2 = Long.valueOf(8000L);
+ SomeArgs noresourceExpectedArgs = SomeArgs.obtain();
+ noresourceExpectedArgs.argi1 = RcsUceAdapter.ERROR_NOT_FOUND;
+ noresourceExpectedArgs.arg1 = Long.valueOf(0L);
+ terminatedMap.put(giveupArgs, giveupExpectedArgs);
+
+ SomeArgs emptyReasonArgs = SomeArgs.obtain();
+ emptyReasonArgs.arg1 = "";
+ emptyReasonArgs.arg2 = Long.valueOf(9000L);
+ SomeArgs emptyReasonExpectedArgs = SomeArgs.obtain();
+ emptyReasonExpectedArgs.argi1 = RcsUceAdapter.ERROR_GENERIC_FAILURE;
+ emptyReasonExpectedArgs.arg1 = Long.valueOf(9000L);
+ terminatedMap.put(emptyReasonArgs, emptyReasonExpectedArgs);
+
+ // Verify each subscription terminated and the expected result
+ terminatedMap.forEach((reason, expectedResult) -> {
+ String terminatedReason = (String) reason.arg1;
+ Long terminatedRetryAfterMillis = (Long) reason.arg2;
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ cb.onNetworkResponse(networkRespCode, networkRespReason);
+ cb.onNotifyCapabilitiesUpdate(pidfXmlList);
+ cb.onTerminated(terminatedReason, terminatedRetryAfterMillis);
+ });
+
+ requestCapabilities(uceAdapter, numbers, callback);
+
+ try {
+ // Verify that the contact capability is received and the onCompleted is called.
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received for contact: " + sTestNumberUri,
+ capability);
+ verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, true);
+
+ int expectedErrorCode = expectedResult.argi1;
+ Long expectedRetryAfter = (Long) expectedResult.arg1;
+ assertEquals(expectedErrorCode, waitForIntResult(errorQueue));
+ assertEquals(expectedRetryAfter.longValue(), (waitForLongResult(errorRetryQueue)));
+ } catch (Exception e) {
+ fail("Unexpected exception " + e);
+ }
+
+ reason.recycle();
+ expectedResult.recycle();
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+ removeTestContactFromEab();
+ });
+
+ /*
+ * Verify the subscribe request is successful when: A) The terminated is timeout and
+ * B) The retryAfter is 0L and C) All the capabilities have been received.
+ */
+ String terminatedReason = "timeout";
+ long terminatedRetryAfterMillis = 0L;
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ cb.onNetworkResponse(networkRespCode, networkRespReason);
+ cb.onNotifyCapabilitiesUpdate(pidfXmlList);
+ cb.onTerminated(terminatedReason, terminatedRetryAfterMillis);
+ });
+
+ requestCapabilities(uceAdapter, numbers, callback);
+
+ // Verify that the contact capability is received and the onCompleted is called.
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received for contact: " + sTestNumberUri, capability);
+ verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, true);
+ assertTrue(waitForResult(completeQueue));
+
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+ removeTestContactFromEab();
+
+ /*
+ * Set the subscribe request is failed because NOT all of the capabilities have been
+ * received.
+ */
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ cb.onNetworkResponse(networkRespCode, networkRespReason);
+ cb.onTerminated(terminatedReason, terminatedRetryAfterMillis);
+ });
+
+ requestCapabilities(uceAdapter, numbers, callback);
+
+ /*
+ * Verify the request is failed because NOT all of the capabilities have been received.
+ */
+ assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+ assertEquals(0L, (waitForLongResult(errorRetryQueue)));
+
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+ removeTestContactFromEab();
+ overrideCarrierConfig(null);
+ }
+
+ @Test
+ public void testTimeoutToRequestCapabilitiesWithPresenceMechanism() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+ RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+ assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+ // Remove the test contact capabilities
+ removeTestContactFromEab();
+
+ // Connect to the ImsService
+ setupTestImsService(uceAdapter, true, true /* presence cap */, false /* OPTIONS */);
+
+ TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+ .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+ BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Long> errorRetryQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
+ RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+ @Override
+ public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+ capabilities.forEach(c -> capabilityQueue.offer(c));
+ }
+ @Override
+ public void onComplete() {
+ completeQueue.offer(true);
+ }
+ @Override
+ public void onError(int errorCode, long retryAfterMilliseconds) {
+ errorQueue.offer(errorCode);
+ errorRetryQueue.offer(retryAfterMilliseconds);
+ }
+ };
+
+ // Prepare three contacts
+ final Uri contact1 = sTestNumberUri;
+ final Uri contact2 = sTestContact2Uri;
+ final Uri contact3 = sTestContact3Uri;
+
+ Collection<Uri> contacts = new ArrayList<>(3);
+ contacts.add(contact1);
+ contacts.add(contact2);
+ contacts.add(contact3);
+
+ // Setup the ImsService doesn't trigger any callbacks.
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ // It won't trigger any callbacks.
+ });
+
+ try {
+ setCapabilitiesRequestTimeout(3000L);
+
+ requestCapabilities(uceAdapter, contacts, callback);
+
+ // Verify that the clients receive the TIMEOUT error code.
+ assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+ assertEquals(0L, (waitForLongResult(errorRetryQueue)));
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+ removeTestContactFromEab();
+ setCapabilitiesRequestTimeout(-1L);
+ }
+
+ // Setup the ImsService only trigger the network response callback. However it doesn't
+ // trigger the onTerminated callback
+ int networkRespCode = 200;
+ String networkRespReason = "OK";
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ cb.onNetworkResponse(networkRespCode, networkRespReason);
+ });
+
+ try {
+ setCapabilitiesRequestTimeout(3000L);
+
+ requestCapabilities(uceAdapter, contacts, callback);
+
+ // Verify that the clients receive the TIMEOUT error code.
+ assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+ assertEquals(0L, (waitForLongResult(errorRetryQueue)));
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+ removeTestContactFromEab();
+ setCapabilitiesRequestTimeout(-1L);
+ }
+
+ overrideCarrierConfig(null);
+ }
+
+
+ @Test
+ public void testTimeoutToRequestCapabilitiesWithOptionsMechanism() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+ RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+ assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+ // Remove the test contact capabilities
+ removeTestContactFromEab();
+
+ // Connect to the ImsService
+ setupTestImsService(uceAdapter, true, false, true /* OPTIONS enabled */);
+
+ TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+ .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+ // The test contact
+ Collection<Uri> contacts = new ArrayList<>(3);
+ contacts.add(sTestNumberUri);
+
+ // The result callback
+ BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Long> errorRetryQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
+ RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+ @Override
+ public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+ capabilities.forEach(c -> capabilityQueue.offer(c));
+ }
+ @Override
+ public void onComplete() {
+ completeQueue.offer(true);
+ }
+ @Override
+ public void onError(int errorCode, long retryAfterMilliseconds) {
+ errorQueue.offer(errorCode);
+ errorRetryQueue.offer(retryAfterMilliseconds);
+ }
+ };
+
+ // Setup the ImsService doesn't trigger any callbacks.
+ capabilityExchangeImpl.setOptionsOperation((contact, myCapabilities, optionsCallback) -> {
+ // It won't trigger any callbacks.
+ });
+
+ try {
+ setCapabilitiesRequestTimeout(3000L);
+
+ requestCapabilities(uceAdapter, contacts, callback);
+
+ // Verify that the clients receive the TIMEOUT error code.
+ assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+ assertEquals(0L, (waitForLongResult(errorRetryQueue)));
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+ removeTestContactFromEab();
+ setCapabilitiesRequestTimeout(-1L);
+ }
+
+ overrideCarrierConfig(null);
+ }
+
private void setupTestImsService(RcsUceAdapter uceAdapter, boolean presencePublishEnabled,
boolean presenceCapExchangeEnabled, boolean sipOptionsEnabled) throws Exception {
// Trigger carrier config changed
@@ -1341,17 +2345,6 @@
bundle.putBoolean(CarrierConfigManager.KEY_USE_RCS_SIP_OPTIONS_BOOL, sipOptionsEnabled);
overrideCarrierConfig(bundle);
- // Enable the UCE setting.
- try {
- ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(
- uceAdapter, adapter -> adapter.setUceSettingEnabled(true), ImsException.class,
- "android.permission.MODIFY_PHONE_STATE");
- } catch (SecurityException e) {
- fail("setUceSettingEnabled should succeed with MODIFY_PHONE_STATE.");
- } catch (ImsException e) {
- fail("setUceSettingEnabled failed with code " + e);
- }
-
// Connect to the TestImsService
connectTestImsService();
}
@@ -1379,17 +2372,18 @@
}
private void verifyCapabilityResult(RcsContactUceCapability resultCapability, Uri expectedUri,
- int expectedResult, boolean expectedAudioSupported, boolean expectedVideoSupported) {
+ int expectedSourceType, int expectedResult, boolean expectedAudioSupported,
+ boolean expectedVideoSupported) {
// Verify the contact URI
assertEquals(expectedUri, resultCapability.getContactUri());
// Verify the source type is the network type.
- assertEquals(RcsContactUceCapability.SOURCE_TYPE_NETWORK,
+ assertEquals(expectedSourceType,
resultCapability.getSourceType());
// Verify the request result is expected.
final int requestResult = resultCapability.getRequestResult();
- assertEquals(requestResult, expectedResult);
+ assertEquals(expectedResult, requestResult);
// Return directly if the result is not found.
if (requestResult == REQUEST_RESULT_NOT_FOUND) {
@@ -1414,6 +2408,30 @@
assertEquals(expectedVideoSupported, capabilities.isVideoCapable());
}
+ private void verifyOptionsCapabilityResult(List<RcsContactUceCapability> resultCapList,
+ Collection<Uri> expectedUriList, int expectedSourceType, int expectedMechanism,
+ int expectedResult, List<String> expectedFeatureTags) {
+ assertEquals(resultCapList.size(), expectedUriList.size());
+
+ assertTrue(resultCapList.stream().map(capability -> capability.getContactUri())
+ .anyMatch(expectedUriList::contains));
+
+ resultCapList.stream().map(capability -> capability.getSourceType())
+ .forEach(sourceType -> assertEquals((int) sourceType, (int) expectedSourceType));
+
+ resultCapList.stream().map(capability -> capability.getCapabilityMechanism())
+ .forEach(mechanism -> assertEquals((int) mechanism, (int) expectedMechanism));
+
+ resultCapList.stream().map(capability -> capability.getRequestResult())
+ .forEach(result -> assertEquals((int) result, (int) expectedResult));
+
+ resultCapList.stream().map(capability -> capability.getFeatureTags())
+ .forEach(featureTags -> {
+ assertEquals((int) featureTags.size(), (int) expectedFeatureTags.size());
+ assertTrue(featureTags.containsAll(expectedFeatureTags));
+ });
+ }
+
private void registerUceObserver(Consumer<Uri> resultConsumer) {
mUceObserver = new ContentObserver(new Handler(sHandlerThread.getLooper())) {
@Override
@@ -1525,7 +2543,23 @@
}
}
- private void requestCapabilities(RcsUceAdapter uceAdapter, List<Uri> numbers,
+ private static void removeUceRequestDisallowedStatus() {
+ try {
+ sServiceConnector.removeUceRequestDisallowedStatus(sTestSlot);
+ } catch (Exception e) {
+ Log.w("RcsUceAdapterTest", "Cannot remove request disallowed status: " + e);
+ }
+ }
+
+ private static void setCapabilitiesRequestTimeout(long timeoutAfterMillis) {
+ try {
+ sServiceConnector.setCapabilitiesRequestTimeout(sTestSlot, timeoutAfterMillis);
+ } catch (Exception e) {
+ Log.w("RcsUceAdapterTest", "Cannot set capabilities request timeout: " + e);
+ }
+ }
+
+ private void requestCapabilities(RcsUceAdapter uceAdapter, Collection<Uri> numbers,
RcsUceAdapter.CapabilitiesCallback callback) {
try {
ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(
@@ -1556,24 +2590,4 @@
fail("requestAvailability failed " + e);
}
}
-
- private void lunchUceActivity() throws Exception {
- final CountDownLatch countdownLatch = new CountDownLatch(1);
- final Intent activityIntent = new Intent(getContext(), UceActivity.class);
- activityIntent.setAction(Intent.ACTION_MAIN);
- activityIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- UceActivity.setCountDownLatch(countdownLatch);
- getContext().startActivity(activityIntent);
- countdownLatch.await(5000, TimeUnit.MILLISECONDS);
- }
-
- private void finishUceActivity() {
- final Intent finishIntent = new Intent(getContext(), UceActivity.class);
- finishIntent.setAction(UceActivity.ACTION_FINISH);
- finishIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- finishIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- finishIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
- getContext().startActivity(finishIntent);
- }
}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/SipDelegateManagerTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/SipDelegateManagerTest.java
index 95935ac..dea6cf3 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/SipDelegateManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/SipDelegateManagerTest.java
@@ -30,6 +30,8 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.net.InetAddresses;
+import android.net.Uri;
import android.os.Parcel;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
@@ -41,6 +43,7 @@
import android.telephony.ims.ImsException;
import android.telephony.ims.ImsManager;
import android.telephony.ims.ImsService;
+import android.telephony.ims.SipDelegateConfiguration;
import android.telephony.ims.SipDelegateImsConfiguration;
import android.telephony.ims.SipDelegateManager;
import android.telephony.ims.SipMessage;
@@ -61,6 +64,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
@@ -83,6 +87,9 @@
private static final String FILE_TRANSFER_HTTP_TAG =
"+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gppapplication.ims.iari.rcs.fthttp\"";
+ private static final String[] DEFAULT_FEATURE_TAGS = {
+ ONE_TO_ONE_CHAT_TAG, GROUP_CHAT_TAG, FILE_TRANSFER_HTTP_TAG};
+
private static class CarrierConfigReceiver extends BroadcastReceiver {
private CountDownLatch mLatch = new CountDownLatch(1);
private final int mSubId;
@@ -110,6 +117,65 @@
}
}
+ /**
+ * Encapsulates the interfaces created during SipDelegateManager testing.
+ */
+ public class TransportInterfaces {
+ public final DelegateRequest request;
+ public final Set<FeatureTagState> deniedTags;
+ public final SipDelegateManager manager;
+ public TestSipTransport transport;
+ public TestImsRegistration reg;
+ public TestSipDelegate delegate;
+ public TestSipDelegateConnection delegateConn;
+ private final int mDelegateIndex;
+
+ public TransportInterfaces(DelegateRequest request, Set<FeatureTagState> deniedTags,
+ int delegateIndex) {
+ this.request = request;
+ this.deniedTags = deniedTags;
+ manager = getSipDelegateManager();
+ mDelegateIndex = delegateIndex;
+ }
+
+ public void connect() throws Exception {
+ assertTrue(sServiceConnector.setDefaultSmsApp());
+ connectTestImsServiceWithSipTransportAndConfig();
+
+ transport = sServiceConnector.getCarrierService().getSipTransport();
+ reg = sServiceConnector.getCarrierService().getImsRegistration();
+ delegateConn = new TestSipDelegateConnection(request);
+
+ delegate = createSipDelegateConnectionAndVerify(manager, delegateConn,
+ transport, deniedTags, mDelegateIndex);
+ assertNotNull(delegate);
+ // ensure we got a callback for initial reg state.
+ verifyUpdateRegistrationCalled(reg);
+
+ InetSocketAddress localAddr = new InetSocketAddress(
+ InetAddresses.parseNumericAddress("1.1.1.1"), 80);
+ InetSocketAddress serverAddr = new InetSocketAddress(
+ InetAddresses.parseNumericAddress("2.2.2.2"), 81);
+ SipDelegateConfiguration c = new SipDelegateConfiguration.Builder(1,
+ SipDelegateConfiguration.SIP_TRANSPORT_TCP, localAddr, serverAddr).build();
+ // send first SIP config and verify
+ verifyRegisteredAndSendSipConfig(delegateConn, delegate, request.getFeatureTags(),
+ deniedTags, c);
+ }
+
+ /**
+ * Create a connection between fake app interface and fake ImsService impl and set up the
+ * framework to accept incoming/outgoing messages. Once done, verify the transport is open.
+ */
+ public void connectAndVerify() throws Exception {
+ connect();
+
+ // Verify message transport is open.
+ verifyOutgoingTransport(delegateConn, delegate);
+ verifyIncomingTransport(delegateConn, delegate);
+ }
+ }
+
private static int sTestSlot = 0;
private static int sTestSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private static ImsServiceConnector sServiceConnector;
@@ -149,6 +215,8 @@
// APIs.
sServiceConnector.setDeviceSingleRegistrationEnabled(true);
}
+
+ setFeatureTagsCarrierAllowed(DEFAULT_FEATURE_TAGS);
}
@AfterClass
@@ -487,7 +555,7 @@
createSipDelegateConnectionNoDelegateExpected(manager, delegateConn, transportImpl);
// TODO deal with this case better when we can filter messages.
- delegateConn.sendMessageAndVerifyFailure(ImsUtils.TEST_SIP_MESSAGE,
+ delegateConn.sendMessageAndVerifyFailure(SipMessageUtils.TEST_SIP_MESSAGE,
SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD);
delegateConn.triggerFullNetworkRegistration(manager, 403, "FORBIDDEN");
@@ -504,6 +572,24 @@
if (!ImsUtils.shouldTestImsService()) {
return;
}
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connectAndVerify();
+
+ // Ensure requests to perform a full network re-registration work properly.
+ verifyFullRegistrationTriggered(ifaces);
+
+ destroySipDelegateAndVerify(ifaces);
+ assertEquals("There should be no more delegates", 0,
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ }
+
+ @Test
+ public void testImsServiceDisconnected() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
assertTrue(sServiceConnector.setDefaultSmsApp());
connectTestImsServiceWithSipTransportAndConfig();
@@ -518,20 +604,71 @@
assertNotNull(delegate);
verifyUpdateRegistrationCalled(regImpl);
- SipDelegateImsConfiguration c = new SipDelegateImsConfiguration.Builder(1)
- .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING, "123")
- .build();
+ InetSocketAddress localAddr = new InetSocketAddress(
+ InetAddresses.parseNumericAddress("1.1.1.1"), 80);
+ InetSocketAddress serverAddr = new InetSocketAddress(
+ InetAddresses.parseNumericAddress("2.2.2.2"), 81);
+ SipDelegateConfiguration c = new SipDelegateConfiguration.Builder(1,
+ SipDelegateConfiguration.SIP_TRANSPORT_TCP, localAddr, serverAddr).build();
verifyRegisteredAndSendSipConfig(delegateConn, delegate, request.getFeatureTags(),
Collections.emptySet(), c);
- sendMessageAndVerifyAck(delegateConn, delegate);
- receiveMessageAndVerifyAck(delegateConn, delegate);
+ verifyOutgoingTransport(delegateConn, delegate);
+ verifyIncomingTransport(delegateConn, delegate);
- // Ensure requests to perform a full network re-registration work properly.
- verifyFullRegistrationTriggered(manager, regImpl, delegateConn);
+ sServiceConnector.disconnectCarrierImsService();
+ // unbind ImsService suddenly and wait for on destroyed
+ delegateConn.setOperationCountDownLatch(1);
+ transportImpl.waitForLatchCountdownAndReset(TestSipTransport.LATCH_DESTROY_DELEGATE);
+ delegate.notifyOnDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
+ delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ delegateConn.verifyDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
+ }
- destroySipDelegateAndVerify(manager, transportImpl, delegateConn, delegate,
- request.getFeatureTags());
+ @Test
+ public void testCreateDelegateTestInvalidSipMessages() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connectAndVerify();
+
+ // Verify restricted SIP request methods are not sent to the delegate.
+ sendRestrictedRequestsAndVerifyFailed(ifaces.delegateConn);
+ // Verify malformed messages are not sent to the delegate.
+ sendInvalidRequestsAndVerifyFailed(ifaces.delegateConn);
+
+ destroySipDelegateAndVerify(ifaces);
+ assertEquals("There should be no more delegates", 0,
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ }
+
+ @Test
+ public void testDeprecatedConfig() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ assertTrue(sServiceConnector.setDefaultSmsApp());
+ connectTestImsServiceWithSipTransportAndConfig();
+
+ TestSipTransport transportImpl = sServiceConnector.getCarrierService().getSipTransport();
+ TestImsRegistration regImpl = sServiceConnector.getCarrierService().getImsRegistration();
+ SipDelegateManager manager = getSipDelegateManager();
+ DelegateRequest request = getDefaultRequest();
+ TestSipDelegateConnection delegateConn = new TestSipDelegateConnection(request);
+
+ TestSipDelegate delegate = createSipDelegateConnectionAndVerify(manager, delegateConn,
+ transportImpl, Collections.emptySet(), 0);
+ assertNotNull(delegate);
+ verifyUpdateRegistrationCalled(regImpl);
+ verifyRegisteredAndSendOldSipConfig(delegateConn, delegate, request.getFeatureTags(),
+ Collections.emptySet());
+
+ destroySipDelegateAndVerifyConnDestroyed(manager, transportImpl, delegateConn, delegate);
assertEquals("There should be no more delegates", 0,
transportImpl.getDelegates().size());
verifyUpdateRegistrationCalled(regImpl);
@@ -542,49 +679,28 @@
if (!ImsUtils.shouldTestImsService()) {
return;
}
- assertTrue(sServiceConnector.setDefaultSmsApp());
- connectTestImsServiceWithSipTransportAndConfig();
-
- TestSipTransport transportImpl = sServiceConnector.getCarrierService().getSipTransport();
- SipDelegateManager manager = getSipDelegateManager();
- DelegateRequest request = getDefaultRequest();
- TestSipDelegateConnection delegateConn = new TestSipDelegateConnection(request);
-
- // Construct registered tags and denied tags, vendor denied FT tag.
- Set<String> registeredTags = new ArraySet<>(request.getFeatureTags());
- registeredTags.remove(FILE_TRANSFER_HTTP_TAG);
- Set<FeatureTagState> deniedTags = new ArraySet<>(1);
- deniedTags.add(new FeatureTagState(FILE_TRANSFER_HTTP_TAG,
- SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE));
- TestSipDelegate delegate = createSipDelegateConnectionAndVerify(manager, delegateConn,
- transportImpl, deniedTags, 0);
- assertNotNull(delegate);
-
- SipDelegateImsConfiguration c = new SipDelegateImsConfiguration.Builder(1)
- .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING, "123")
- .build();
- verifyRegisteredAndSendSipConfig(delegateConn, delegate, registeredTags, deniedTags, c);
-
- // TODO verify messages can be sent on registered tags, but generate error for denied tags.
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connectAndVerify();
+ Set<String> registeredTags = new ArraySet<>(ifaces.request.getFeatureTags());
// move reg state to deregistering and then deregistered
- delegateConn.setOperationCountDownLatch(1);
+ ifaces.delegateConn.setOperationCountDownLatch(1);
DelegateRegistrationState s = getDeregisteringState(registeredTags,
DelegateRegistrationState.DEREGISTERING_REASON_PDN_CHANGE);
- delegate.notifyImsRegistrationUpdate(s);
- delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
- delegateConn.verifyRegistrationStateEquals(s);
+ ifaces.delegate.notifyImsRegistrationUpdate(s);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ ifaces.delegateConn.verifyRegistrationStateEquals(s);
- delegateConn.setOperationCountDownLatch(1);
+ ifaces.delegateConn.setOperationCountDownLatch(1);
s = getRegisteredRegistrationState(registeredTags);
- delegate.notifyImsRegistrationUpdate(s);
- delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
- delegateConn.verifyRegistrationStateEquals(s);
+ ifaces.delegate.notifyImsRegistrationUpdate(s);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ ifaces.delegateConn.verifyRegistrationStateEquals(s);
- destroySipDelegateAndVerify(manager, transportImpl, delegateConn, delegate,
- registeredTags);
+ destroySipDelegateAndVerify(ifaces);
assertEquals("There should be no more delegates", 0,
- transportImpl.getDelegates().size());
+ ifaces.transport.getDelegates().size());
}
@Test
@@ -605,9 +721,12 @@
transportImpl, Collections.emptySet(), 0);
assertNotNull(delegate1);
- SipDelegateImsConfiguration c = new SipDelegateImsConfiguration.Builder(1)
- .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING, "123")
- .build();
+ InetSocketAddress localAddr = new InetSocketAddress(
+ InetAddresses.parseNumericAddress("1.1.1.1"), 80);
+ InetSocketAddress serverAddr = new InetSocketAddress(
+ InetAddresses.parseNumericAddress("2.2.2.2"), 81);
+ SipDelegateConfiguration c = new SipDelegateConfiguration.Builder(1,
+ SipDelegateConfiguration.SIP_TRANSPORT_TCP, localAddr, serverAddr).build();
verifyRegisteredAndSendSipConfig(delegateConn1, delegate1, registeredTags1,
Collections.emptySet(), c);
@@ -627,21 +746,16 @@
deniedSet, c);
// Destroying delegate 1 will transfer all feature tags over to delegate 2
- delegateConn2.setOperationCountDownLatch(1);
- destroySipDelegateAndVerify(manager, transportImpl, delegateConn1, delegate1,
- registeredTags1);
- delegateConn2.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ destroySipDelegate(manager, transportImpl, delegateConn1, delegate1);
// This internally triggers the destruction of the internal delegate2 and then recreation
// of another delegate with the new feature set that it supports.
- verifySipDelegateDestroyed(transportImpl, delegateConn2, delegate2, registeredTags2,
- DelegateRegistrationState.DEREGISTERING_REASON_FEATURE_TAGS_CHANGING);
+ verifySipDelegateDestroyed(transportImpl, delegate2);
delegate2 = getSipDelegate(transportImpl, Collections.emptySet(), 0);
verifyUpdateRegistrationCalled(regImpl);
verifyRegisteredAndSendSipConfig(delegateConn2, delegate2, request2.getFeatureTags(),
Collections.emptySet(), c);
- destroySipDelegateAndVerify(manager, transportImpl, delegateConn2, delegate2,
- request2.getFeatureTags());
+ destroySipDelegateAndVerifyConnDestroyed(manager, transportImpl, delegateConn2, delegate2);
assertEquals("There should be no more delegates", 0,
transportImpl.getDelegates().size());
}
@@ -670,13 +784,15 @@
ImsUtils.TEST_TIMEOUT_MS));
TestSipDelegate delegate = getSipDelegate(transportImpl, Collections.emptySet(), 0);
verifyUpdateRegistrationCalled(regImpl);
- SipDelegateImsConfiguration c = new SipDelegateImsConfiguration.Builder(1)
- .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING, "123")
- .build();
+ InetSocketAddress localAddr = new InetSocketAddress(
+ InetAddresses.parseNumericAddress("1.1.1.1"), 80);
+ InetSocketAddress serverAddr = new InetSocketAddress(
+ InetAddresses.parseNumericAddress("2.2.2.2"), 81);
+ SipDelegateConfiguration c = new SipDelegateConfiguration.Builder(1,
+ SipDelegateConfiguration.SIP_TRANSPORT_TCP, localAddr, serverAddr).build();
verifyRegisteredAndSendSipConfig(delegateConn, delegate, request.getFeatureTags(),
Collections.emptySet(), c);
- destroySipDelegateAndVerify(manager, transportImpl, delegateConn, delegate,
- request.getFeatureTags());
+ destroySipDelegateAndVerifyConnDestroyed(manager, transportImpl, delegateConn, delegate);
assertEquals("There should be no more delegates", 0,
transportImpl.getDelegates().size());
}
@@ -687,49 +803,30 @@
return;
}
// Make this app the DMA
- assertTrue(sServiceConnector.setDefaultSmsApp());
- connectTestImsServiceWithSipTransportAndConfig();
- TestSipTransport transportImpl = sServiceConnector.getCarrierService().getSipTransport();
- TestImsRegistration regImpl = sServiceConnector.getCarrierService().getImsRegistration();
- SipDelegateManager manager = getSipDelegateManager();
-
- DelegateRequest request = getDefaultRequest();
- TestSipDelegateConnection delegateConn = new TestSipDelegateConnection(request);
- TestSipDelegate delegate = createSipDelegateConnectionAndVerify(manager, delegateConn,
- transportImpl, Collections.emptySet(), 0);
- assertNotNull(delegate);
- verifyUpdateRegistrationCalled(regImpl);
-
- SipDelegateImsConfiguration c = new SipDelegateImsConfiguration.Builder(1)
- .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING, "123")
- .build();
- verifyRegisteredAndSendSipConfig(delegateConn, delegate, request.getFeatureTags(),
- Collections.emptySet(), c);
-
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connectAndVerify();
// Move DMA to another app, we should receive a registration update.
- delegateConn.setOperationCountDownLatch(1);
- regImpl.resetLatch(TestImsRegistration.LATCH_TRIGGER_DEREGISTRATION, 1);
+ ifaces.reg.resetLatch(TestImsRegistration.LATCH_TRIGGER_DEREGISTRATION, 1);
sServiceConnector.restoreDefaultSmsApp();
- assertTrue(regImpl.waitForLatchCountDown(TestImsRegistration.LATCH_TRIGGER_DEREGISTRATION,
- ImsUtils.TEST_TIMEOUT_MS));
- delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ assertTrue(ifaces.reg.waitForLatchCountDown(
+ TestImsRegistration.LATCH_TRIGGER_DEREGISTRATION, ImsUtils.TEST_TIMEOUT_MS));
// we should get another reg update with all tags denied.
- delegateConn.setOperationCountDownLatch(1);
- verifySipDelegateDestroyed(transportImpl, delegateConn, delegate, request.getFeatureTags(),
- DelegateRegistrationState.DEREGISTERING_REASON_FEATURE_TAGS_CHANGING);
- delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
- delegateConn.verifyRegistrationStateEmpty();
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ verifySipDelegateDestroyed(ifaces.transport, ifaces.delegate);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ ifaces.delegateConn.verifyRegistrationStateEmpty();
// All requested features should have been denied due to the app not being the default sms
// app.
- delegateConn.verifyAllDenied(SipDelegateManager.DENIED_REASON_NOT_ALLOWED);
+ ifaces.delegateConn.verifyAllDenied(SipDelegateManager.DENIED_REASON_NOT_ALLOWED);
// There should not be any delegates left, as the only delegate should have been cleaned up.
assertEquals("SipDelegate should not have any delegates", 0,
- transportImpl.getDelegates().size());
- verifyUpdateRegistrationCalled(regImpl);
-
- destroySipDelegateConnectionNoDelegate(manager, delegateConn);
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ destroySipDelegateConnectionNoDelegate(ifaces.manager, ifaces.delegateConn);
}
+
@Test
public void testParcelUnparcelDelegateRequest() {
ArraySet<String> testTags = new ArraySet<>();
@@ -782,29 +879,86 @@
}
@Test
- public void testParcelUnparcelImsConfiguration() {
- SipDelegateImsConfiguration c = new SipDelegateImsConfiguration.Builder(1 /*version*/)
- .addBoolean(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL, true)
- .addInt(SipDelegateImsConfiguration.KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT, 1)
- .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING, "123")
- .build();
+ public void testParcelUnparcelConfiguration() {
+ // Set everything to a non-default value
+ SipDelegateConfiguration c = generateNewTestConfig();
+ assertEquals(1, c.getVersion());
+ assertEquals(SipDelegateConfiguration.SIP_TRANSPORT_TCP, c.getTransportType());
+ assertEquals("1.1.1.1", c.getLocalAddress().getAddress().getHostAddress());
+ assertEquals(80, c.getLocalAddress().getPort());
+ assertEquals("2.2.2.2", c.getSipServerAddress().getAddress().getHostAddress());
+ assertEquals(81, c.getSipServerAddress().getPort());
+ assertTrue(c.isSipCompactFormEnabled());
+ assertTrue(c.isSipKeepaliveEnabled());
+ assertEquals(508, c.getMaxUdpPayloadSizeBytes());
+ assertEquals("test1", c.getPublicUserIdentifier());
+ assertEquals("test2", c.getPrivateUserIdentifier());
+ assertEquals("test.domain", c.getHomeDomain());
+ assertEquals("testImei", c.getImei());
+ assertEquals("sipauth", c.getSipAuthenticationHeader());
+ assertEquals("sipnonce", c.getSipAuthenticationNonce());
+ assertEquals("srvroute", c.getSipServiceRouteHeader());
+ assertEquals("path", c.getSipPathHeader());
+ assertEquals("ua", c.getSipUserAgentHeader());
+ assertEquals("user", c.getSipContactUserParameter());
+ assertEquals("pani", c.getSipPaniHeader());
+ assertEquals("plani", c.getSipPlaniHeader());
+ assertEquals("cni", c.getSipCniHeader());
+ assertEquals("uri", c.getSipAssociatedUriHeader());
+ Uri gruuUri = Uri.parse("sip:blah@gruu.net");
+ assertEquals(gruuUri, c.getPublicGruuUri());
+
Parcel p = Parcel.obtain();
c.writeToParcel(p, 0);
p.setDataPosition(0);
- SipDelegateImsConfiguration unparcel =
- SipDelegateImsConfiguration.CREATOR.createFromParcel(p);
- assertEquals(c.getVersion(), unparcel.getVersion());
- assertEquals(c.getBoolean(
- SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL, false),
- unparcel.getBoolean(
- SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL, false));
- assertEquals(c.getInt(
- SipDelegateImsConfiguration.KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT, -1),
- unparcel.getInt(
- SipDelegateImsConfiguration.KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT,
- -1));
- assertEquals(c.getString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING),
- unparcel.getString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING));
+ SipDelegateConfiguration unparcelConfig =
+ SipDelegateConfiguration.CREATOR.createFromParcel(p);
+ assertEquals(c, unparcelConfig);
+ }
+
+ @Test
+ public void testCopyConfiguration() {
+ // Set everything to a non-default value
+ SipDelegateConfiguration c = generateNewTestConfig();
+ // The config should be exactly the same, but with an incremented version.
+ SipDelegateConfiguration configInc = new SipDelegateConfiguration.Builder(c).build();
+ assertEquals(2, configInc.getVersion());
+ assertEquals(SipDelegateConfiguration.SIP_TRANSPORT_TCP, configInc.getTransportType());
+ assertEquals("1.1.1.1", configInc.getLocalAddress().getAddress().getHostAddress());
+ assertEquals(80, configInc.getLocalAddress().getPort());
+ assertEquals("2.2.2.2",
+ configInc.getSipServerAddress().getAddress().getHostAddress());
+ assertEquals(81, configInc.getSipServerAddress().getPort());
+ assertTrue(configInc.isSipCompactFormEnabled());
+ assertTrue(configInc.isSipKeepaliveEnabled());
+ assertEquals(508, configInc.getMaxUdpPayloadSizeBytes());
+ assertEquals("test1", configInc.getPublicUserIdentifier());
+ assertEquals("test2", configInc.getPrivateUserIdentifier());
+ assertEquals("test.domain", configInc.getHomeDomain());
+ assertEquals("testImei", configInc.getImei());
+ assertEquals("sipauth", configInc.getSipAuthenticationHeader());
+ assertEquals("sipnonce", configInc.getSipAuthenticationNonce());
+ assertEquals("srvroute", configInc.getSipServiceRouteHeader());
+ assertEquals("path", configInc.getSipPathHeader());
+ assertEquals("ua", configInc.getSipUserAgentHeader());
+ assertEquals("user", configInc.getSipContactUserParameter());
+ assertEquals("pani", configInc.getSipPaniHeader());
+ assertEquals("plani", configInc.getSipPlaniHeader());
+ assertEquals("cni", configInc.getSipCniHeader());
+ assertEquals("uri", configInc.getSipAssociatedUriHeader());
+ Uri gruuUri = Uri.parse("sip:blah@gruu.net");
+ assertEquals(gruuUri, configInc.getPublicGruuUri());
+ SipDelegateConfiguration.IpSecConfiguration ipSecConfig = configInc.getIpSecConfiguration();
+ assertEquals(123, ipSecConfig.getLocalTxPort());
+ assertEquals(124, ipSecConfig.getLocalRxPort());
+ assertEquals(125, ipSecConfig.getLastLocalTxPort());
+ assertEquals(126, ipSecConfig.getRemoteTxPort());
+ assertEquals(127, ipSecConfig.getRemoteRxPort());
+ assertEquals(128, ipSecConfig.getLastRemoteTxPort());
+ assertEquals("secverify", ipSecConfig.getSipSecurityVerifyHeader());
+ InetSocketAddress natAddr = configInc.getNatSocketAddress();
+ assertEquals("3.3.3.3", natAddr.getAddress().getHostAddress());
+ assertEquals(129, natAddr.getPort());
}
@Test
@@ -854,7 +1008,7 @@
byte[] content2 = new byte[0];
SipMessage m = new SipMessage(startLine, header, content1);
- byte[] encodedMsg = m.getEncodedMessage();
+ byte[] encodedMsg = m.toEncodedMessage();
String decodedStr = new String(encodedMsg, UTF_8);
SipMessage decodedMsg = generateSipMessage(decodedStr);
assertEquals(decodedMsg.getStartLine(), m.getStartLine());
@@ -863,7 +1017,7 @@
// Test empty content
m = new SipMessage(startLine, header, content2);
- encodedMsg = m.getEncodedMessage();
+ encodedMsg = m.toEncodedMessage();
decodedStr = new String(encodedMsg, UTF_8);
decodedMsg = generateSipMessage(decodedStr);
assertEquals(decodedMsg.getStartLine(), m.getStartLine());
@@ -871,6 +1025,638 @@
assertTrue(Arrays.equals(decodedMsg.getContent(), m.getContent()));
}
+ @Test
+ public void testFeatureTagDeniedByCarrierConfig() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+
+ setFeatureTagsCarrierAllowed(new String[]{FILE_TRANSFER_HTTP_TAG});
+ assertTrue(sServiceConnector.setDefaultSmsApp());
+ connectTestImsServiceWithSipTransportAndConfig();
+ TestSipTransport transportImpl = sServiceConnector.getCarrierService().getSipTransport();
+ SipDelegateManager manager = getSipDelegateManager();
+ DelegateRequest request = getDefaultRequest();
+ TestSipDelegateConnection delegateConn = new TestSipDelegateConnection(request);
+ Set<String> deniedTags = new ArraySet<>(request.getFeatureTags());
+ deniedTags.remove(FILE_TRANSFER_HTTP_TAG);
+
+ TestSipDelegate delegate = createSipDelegateConnectionAndVerify(manager, delegateConn,
+ transportImpl, getDeniedTagsForReason(deniedTags,
+ SipDelegateManager.DENIED_REASON_NOT_ALLOWED), 0);
+ assertNotNull(delegate);
+
+ Set<String> registeredTags = new ArraySet<>(
+ Arrays.asList(new String[]{FILE_TRANSFER_HTTP_TAG}));
+ delegateConn.setOperationCountDownLatch(1);
+ DelegateRegistrationState s = getRegisteredRegistrationState(registeredTags);
+ delegate.notifyImsRegistrationUpdate(s);
+ delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ delegateConn.verifyRegistrationStateEquals(s);
+ destroySipDelegateAndVerifyConnDestroyed(manager, transportImpl, delegateConn, delegate);
+ assertEquals("There should be no more delegates", 0,
+ transportImpl.getDelegates().size());
+ setFeatureTagsCarrierAllowed(getDefaultRequest().getFeatureTags().toArray(new String[0]));
+ }
+
+ @Test
+ public void testCloseActiveDialog() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connect();
+ // Send invite
+ SipDialogAttributes attr = new SipDialogAttributes();
+ sendChatInvite(attr, ifaces);
+ // send close from app
+ ifaces.delegateConn.disconnect(ifaces.manager,
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ // Registration state will change to deregistering during this time.
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ assertTrue(ifaces.delegateConn.verifyDeregisteringStateContains(ONE_TO_ONE_CHAT_TAG,
+ DelegateRegistrationState.DEREGISTERING_REASON_DESTROY_PENDING));
+ // receive 200 OK
+ receive200OkResponse(attr, ifaces);
+ // Send ACK
+ sendAck(attr, ifaces);
+ // Send BYE
+ sendByeRequest(attr, ifaces);
+ // destroy should not be called until cleanupSession is sent.
+ assertFalse(ifaces.transport.isLatchCountDownFinished(
+ TestSipTransport.LATCH_DESTROY_DELEGATE));
+
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ // Send the cleanup, which will trigger destroy to complete.
+ ifaces.delegateConn.sendCleanupSession(attr.callId);
+ ifaces.delegate.verifyCleanupSession(attr.callId);
+ ifaces.transport.waitForLatchCountdownAndReset(TestSipTransport.LATCH_DESTROY_DELEGATE);
+ ifaces.delegate.notifyOnDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ ifaces.delegateConn.verifyDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+
+ assertEquals("There should be no more delegates", 0,
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ }
+
+ @Test
+ public void testReceivedActiveDialogClose() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connect();
+ // receive invite
+ SipDialogAttributes attr = new SipDialogAttributes();
+ receiveChatInvite(attr, ifaces);
+ // send close from app
+ ifaces.delegateConn.disconnect(ifaces.manager,
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ // Registration state will change to deregistering during this time.
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ assertTrue(ifaces.delegateConn.verifyDeregisteringStateContains(ONE_TO_ONE_CHAT_TAG,
+ DelegateRegistrationState.DEREGISTERING_REASON_DESTROY_PENDING));
+ // Send 200 OK
+ send200OkResponse(attr, ifaces);
+ // receive ACK
+ receiveAck(attr, ifaces);
+ // Send BYE
+ receiveByeRequest(attr, ifaces);
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ // Send the cleanup, which will trigger destroy to complete.
+ ifaces.delegateConn.sendCleanupSession(attr.callId);
+ ifaces.delegate.verifyCleanupSession(attr.callId);
+ ifaces.transport.waitForLatchCountdownAndReset(TestSipTransport.LATCH_DESTROY_DELEGATE);
+ ifaces.delegate.notifyOnDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ ifaces.delegateConn.verifyDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+
+ assertEquals("There should be no more delegates", 0,
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ }
+
+ @Test
+ public void testActiveDialogPendingNewInvite() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connect();
+ // Send invite
+ SipDialogAttributes attr = new SipDialogAttributes();
+ sendChatInvite(attr, ifaces);
+ // send close from app
+ ifaces.delegateConn.disconnect(ifaces.manager,
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ // Registration state will change to deregistering during this time.
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ assertTrue(ifaces.delegateConn.verifyDeregisteringStateContains(ONE_TO_ONE_CHAT_TAG,
+ DelegateRegistrationState.DEREGISTERING_REASON_DESTROY_PENDING));
+ // receive 200 OK
+ receive200OkResponse(attr, ifaces);
+ // Send ACK
+ sendAck(attr, ifaces);
+ // Send invite
+ SipDialogAttributes attr2 = new SipDialogAttributes();
+ attr2.addAcceptContactTag(ONE_TO_ONE_CHAT_TAG);
+ // Should be denied because the transport is now restricted
+ sendDeniedChatInvite(attr2, ifaces,
+ SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED);
+ // Send BYE on original invite
+ sendByeRequest(attr, ifaces);
+ // destroy should not be called until cleanupSession is sent.
+ assertFalse(ifaces.transport.isLatchCountDownFinished(
+ TestSipTransport.LATCH_DESTROY_DELEGATE));
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ // Send the cleanup, which will trigger destroy to complete.
+ ifaces.delegateConn.sendCleanupSession(attr.callId);
+ ifaces.delegate.verifyCleanupSession(attr.callId);
+ ifaces.transport.waitForLatchCountdownAndReset(TestSipTransport.LATCH_DESTROY_DELEGATE);
+ ifaces.delegate.notifyOnDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ ifaces.delegateConn.verifyDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+
+ assertEquals("There should be no more delegates", 0,
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ }
+
+ @Test
+ public void testCloseSessionByePendingCleanup() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connect();
+ // Send invite
+ SipDialogAttributes attr = new SipDialogAttributes();
+ sendChatInvite(attr, ifaces);
+ // send close from app
+ ifaces.delegateConn.disconnect(ifaces.manager,
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ // receive 200 OK
+ receive200OkResponse(attr, ifaces);
+ // Send ACK
+ sendAck(attr, ifaces);
+ // Send BYE
+ sendByeRequest(attr, ifaces);
+ assertFalse(ifaces.transport.isLatchCountDownFinished(
+ TestSipTransport.LATCH_DESTROY_DELEGATE));
+ // Registration state will change to deregistering during this time.
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ assertTrue(ifaces.delegateConn.verifyDeregisteringStateContains(ONE_TO_ONE_CHAT_TAG,
+ DelegateRegistrationState.DEREGISTERING_REASON_DESTROY_PENDING));
+ // waiting for delegate connection onDestroy to be called.
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ // no cleanupSession called, so cleanup session should be called from internal and then
+ // the delegate should be closed.
+ ifaces.delegate.verifyCleanupSession(attr.callId);
+ ifaces.transport.waitForLatchCountdownAndReset(TestSipTransport.LATCH_DESTROY_DELEGATE);
+ ifaces.delegate.notifyOnDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ ifaces.delegateConn.verifyDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ assertEquals("There should be no more delegates", 0,
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ }
+
+ @Test
+ public void testCloseSessionPendingBye() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connect();
+ // Send invite
+ SipDialogAttributes attr = new SipDialogAttributes();
+ sendChatInvite(attr, ifaces);
+ // send close from app
+ ifaces.delegateConn.disconnect(ifaces.manager,
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ // receive 200 OK
+ receive200OkResponse(attr, ifaces);
+ // Send ACK
+ sendAck(attr, ifaces);
+ // Don't send BYE or cleanupSession
+ assertFalse(ifaces.transport.isLatchCountDownFinished(
+ TestSipTransport.LATCH_DESTROY_DELEGATE));
+ // Registration state will change to deregistering during this time.
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ assertTrue(ifaces.delegateConn.verifyDeregisteringStateContains(ONE_TO_ONE_CHAT_TAG,
+ DelegateRegistrationState.DEREGISTERING_REASON_DESTROY_PENDING));
+ // waiting for delegate connection onDestroy to be called.
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ // no cleanupSession called, so cleanup session should be called from internal and then
+ // the delegate should be closed.
+ ifaces.delegate.verifyCleanupSession(attr.callId);
+ ifaces.transport.waitForLatchCountdownAndReset(TestSipTransport.LATCH_DESTROY_DELEGATE);
+ ifaces.delegate.notifyOnDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ ifaces.delegateConn.verifyDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ assertEquals("There should be no more delegates", 0,
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ }
+
+ @Test
+ public void testCloseMultipleSessionsPendingBye() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connect();
+ // Send invite 1
+ SipDialogAttributes attr = new SipDialogAttributes();
+ sendChatInvite(attr, ifaces);
+ // Send invite 2
+ SipDialogAttributes attr2 = new SipDialogAttributes();
+ sendChatInvite(attr2, ifaces);
+ // send close from app
+ ifaces.delegateConn.disconnect(ifaces.manager,
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ // receive 200 OK
+ receive200OkResponse(attr, ifaces);
+ receive200OkResponse(attr2, ifaces);
+ // Send ACK
+ sendAck(attr, ifaces);
+ sendAck(attr2, ifaces);
+ // Don't send BYE or cleanupSession
+ assertFalse(ifaces.transport.isLatchCountDownFinished(
+ TestSipTransport.LATCH_DESTROY_DELEGATE));
+ // Registration state will change to deregistering during this time.
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ assertTrue(ifaces.delegateConn.verifyDeregisteringStateContains(ONE_TO_ONE_CHAT_TAG,
+ DelegateRegistrationState.DEREGISTERING_REASON_DESTROY_PENDING));
+ // waiting for delegate connection onDestroy to be called.
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ // no cleanupSession called, so cleanup session should be called from internal and then
+ // the delegate should be closed.
+ ifaces.delegate.verifyCleanupSession(attr.callId, attr2.callId);
+ ifaces.transport.waitForLatchCountdownAndReset(TestSipTransport.LATCH_DESTROY_DELEGATE);
+ ifaces.delegate.notifyOnDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ ifaces.delegateConn.verifyDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ assertEquals("There should be no more delegates", 0,
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ }
+
+ @Test
+ public void testCloseSessionBye() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connect();
+ // Send invite
+ SipDialogAttributes attr = new SipDialogAttributes();
+ sendChatInvite(attr, ifaces);
+ // receive 200 OK
+ receive200OkResponse(attr, ifaces);
+ // Send ACK
+ sendAck(attr, ifaces);
+ // send close from app
+ ifaces.delegateConn.disconnect(ifaces.manager,
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ // Send BYE
+ sendByeRequest(attr, ifaces);
+ assertFalse(ifaces.transport.isLatchCountDownFinished(
+ TestSipTransport.LATCH_DESTROY_DELEGATE));
+ // Registration state will change to deregistering during this time.
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ assertTrue(ifaces.delegateConn.verifyDeregisteringStateContains(ONE_TO_ONE_CHAT_TAG,
+ DelegateRegistrationState.DEREGISTERING_REASON_DESTROY_PENDING));
+ // waiting for delegate connection onDestroy to be called.
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ // Send the cleanup, which will trigger destroy to complete.
+ ifaces.delegateConn.sendCleanupSession(attr.callId);
+ ifaces.delegate.verifyCleanupSession(attr.callId);
+ ifaces.transport.waitForLatchCountdownAndReset(TestSipTransport.LATCH_DESTROY_DELEGATE);
+ ifaces.delegate.notifyOnDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ ifaces.delegateConn.verifyDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ assertEquals("There should be no more delegates", 0,
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ }
+
+ @Test
+ public void testSwitchAppPendingBye() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connect();
+ // Send invite
+ SipDialogAttributes attr = new SipDialogAttributes();
+ sendChatInvite(attr, ifaces);
+ // receive 200 OK
+ receive200OkResponse(attr, ifaces);
+ // Restore the default SMS app.
+ sServiceConnector.restoreDefaultSmsApp();
+ // Registration state will change to deregistering during this time.
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ assertTrue(ifaces.delegateConn.verifyDeregisteringStateContains(ONE_TO_ONE_CHAT_TAG,
+ DelegateRegistrationState.DEREGISTERING_REASON_FEATURE_TAGS_CHANGING));
+ // Don't send BYE or cleanup, session should still be cleaned up.
+ assertFalse(ifaces.transport.isLatchCountDownFinished(
+ TestSipTransport.LATCH_DESTROY_DELEGATE));
+ // wait for delegate connection feature tag state to be updated with denied features.
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ // verify framework internally calls cleanup on the session before destroy.
+ ifaces.delegate.verifyCleanupSession(attr.callId);
+ ifaces.transport.waitForLatchCountdownAndReset(TestSipTransport.LATCH_DESTROY_DELEGATE);
+ ifaces.delegate.notifyOnDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ assertEquals("There should be no more delegates", 0,
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ ifaces.delegateConn.verifyRegistrationStateEmpty();
+ ifaces.delegateConn.verifyAllDenied(SipDelegateManager.DENIED_REASON_NOT_ALLOWED);
+ }
+
+ @Test
+ public void testSwitchAppActiveSession() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connect();
+ // Send invite
+ SipDialogAttributes attr = new SipDialogAttributes();
+ sendChatInvite(attr, ifaces);
+ // receive 200 OK
+ receive200OkResponse(attr, ifaces);
+ // Restore the default SMS app.
+ sServiceConnector.restoreDefaultSmsApp();
+ // Registration state will change to deregistering during this time.
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ assertTrue(ifaces.delegateConn.verifyDeregisteringStateContains(ONE_TO_ONE_CHAT_TAG,
+ DelegateRegistrationState.DEREGISTERING_REASON_FEATURE_TAGS_CHANGING));
+ // BYE should still be able to be sent
+ sendByeRequest(attr, ifaces);
+ assertFalse(ifaces.transport.isLatchCountDownFinished(
+ TestSipTransport.LATCH_DESTROY_DELEGATE));
+ // wait for delegate connection feature tag state to be updated with denied features.
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ // Send the cleanup, which will trigger delegate destroy to complete.
+ ifaces.delegateConn.sendCleanupSession(attr.callId);
+ ifaces.delegate.verifyCleanupSession(attr.callId);
+ ifaces.transport.waitForLatchCountdownAndReset(TestSipTransport.LATCH_DESTROY_DELEGATE);
+ ifaces.delegate.notifyOnDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ assertEquals("There should be no more delegates", 0,
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ ifaces.delegateConn.verifyAllDenied(SipDelegateManager.DENIED_REASON_NOT_ALLOWED);
+ }
+
+ @Test
+ public void testActiveSessionDeregistering() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connect();
+ // Send invite
+ SipDialogAttributes attr = new SipDialogAttributes();
+ sendChatInvite(attr, ifaces);
+ // move chat to deregistering
+ Set<String> regFeatures = new ArraySet<>(Arrays.asList(DEFAULT_FEATURE_TAGS));
+ regFeatures.remove(ONE_TO_ONE_CHAT_TAG);
+ DelegateRegistrationState state = getDeregisteringState(regFeatures,
+ Collections.singleton(ONE_TO_ONE_CHAT_TAG),
+ DelegateRegistrationState.DEREGISTERING_REASON_PROVISIONING_CHANGE);
+ verifyRegistrationState(ifaces, state);
+ // receive 200 OK
+ receive200OkResponse(attr, ifaces);
+ // Send ACK
+ sendAck(attr, ifaces);
+ // Send BYE and clean up
+ sendByeRequest(attr, ifaces);
+ ifaces.delegateConn.sendCleanupSession(attr.callId);
+ ifaces.delegate.verifyCleanupSession(attr.callId);
+
+ destroySipDelegateAndVerify(ifaces);
+ assertEquals("There should be no more delegates", 0,
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ }
+
+ @Test
+ public void testActiveSessionDeregisteringNoResponse() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connect();
+ // Send invite
+ SipDialogAttributes attr = new SipDialogAttributes();
+ sendChatInvite(attr, ifaces);
+ // move chat to deregistering
+ Set<String> regFeatures = new ArraySet<>(Arrays.asList(DEFAULT_FEATURE_TAGS));
+ regFeatures.remove(ONE_TO_ONE_CHAT_TAG);
+ DelegateRegistrationState state = getDeregisteringState(regFeatures,
+ Collections.singleton(ONE_TO_ONE_CHAT_TAG),
+ DelegateRegistrationState.DEREGISTERING_REASON_PROVISIONING_CHANGE);
+ verifyRegistrationState(ifaces, state);
+ // receive 200 OK
+ receive200OkResponse(attr, ifaces);
+ // Send ACK
+ sendAck(attr, ifaces);
+ // Don't send BYE or cleanup and ensure that we still get call to clean up after timeout.
+ ifaces.delegate.verifyCleanupSession(attr.callId);
+
+ destroySipDelegateAndVerify(ifaces);
+ assertEquals("There should be no more delegates", 0,
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ }
+
+ @Test
+ public void testMultipleActiveSessionDeregisteringNoResponse() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connect();
+ // Send invite 1
+ SipDialogAttributes attr = new SipDialogAttributes();
+ sendChatInvite(attr, ifaces);
+ // Send invite 2
+ SipDialogAttributes attr2 = new SipDialogAttributes();
+ sendChatInvite(attr2, ifaces);
+ // move chat to deregistering
+ Set<String> regFeatures = new ArraySet<>(Arrays.asList(DEFAULT_FEATURE_TAGS));
+ regFeatures.remove(ONE_TO_ONE_CHAT_TAG);
+ DelegateRegistrationState state = getDeregisteringState(regFeatures,
+ Collections.singleton(ONE_TO_ONE_CHAT_TAG),
+ DelegateRegistrationState.DEREGISTERING_REASON_PROVISIONING_CHANGE);
+ verifyRegistrationState(ifaces, state);
+ // receive 200 OK for invite 1
+ receive200OkResponse(attr, ifaces);
+ // Don't send BYE or cleanup and ensure that we still get call to clean up after timeout.
+ ifaces.delegate.verifyCleanupSession(attr.callId, attr2.callId);
+ destroySipDelegateAndVerify(ifaces);
+ assertEquals("There should be no more delegates", 0,
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ }
+
+ @Test
+ public void testActiveSessionDeregisteringNewInviteDenied() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connect();
+ // Send invite
+ SipDialogAttributes attr = new SipDialogAttributes();
+ sendChatInvite(attr, ifaces);
+ // move chat to deregistering
+ Set<String> regFeatures = new ArraySet<>(Arrays.asList(DEFAULT_FEATURE_TAGS));
+ regFeatures.remove(ONE_TO_ONE_CHAT_TAG);
+ DelegateRegistrationState state = getDeregisteringState(regFeatures,
+ Collections.singleton(ONE_TO_ONE_CHAT_TAG),
+ DelegateRegistrationState.DEREGISTERING_REASON_PROVISIONING_CHANGE);
+ verifyRegistrationState(ifaces, state);
+ // receive 200 OK
+ receive200OkResponse(attr, ifaces);
+ // Send ACK
+ sendAck(attr, ifaces);
+ // send a new invite over the same feature tag, which should be denied because the tag
+ // is deregistering
+ SipDialogAttributes attr2 = new SipDialogAttributes();
+ attr2.addAcceptContactTag(ONE_TO_ONE_CHAT_TAG);
+ sendDeniedChatInvite(attr2, ifaces,
+ SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG);
+ // Send BYE and clean up
+ sendByeRequest(attr, ifaces);
+ ifaces.delegateConn.sendCleanupSession(attr.callId);
+ ifaces.delegate.verifyCleanupSession(attr.callId);
+
+ destroySipDelegateAndVerify(ifaces);
+ assertEquals("There should be no more delegates", 0,
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ }
+
+ @Test
+ public void testInviteDeniedTag() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ // Deny ONE_TO_ONE_CHAT access to this delegate
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.singleton(new FeatureTagState(ONE_TO_ONE_CHAT_TAG,
+ SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE)), 0);
+ ifaces.connect();
+ // send a new invite over the chat feature tag, which should be denied because the tag was
+ // denied
+ SipDialogAttributes attr = new SipDialogAttributes();
+ attr.addAcceptContactTag(ONE_TO_ONE_CHAT_TAG);
+ sendDeniedChatInvite(attr, ifaces,
+ SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG);
+
+ destroySipDelegateAndVerify(ifaces);
+ assertEquals("There should be no more delegates", 0,
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ }
+
+ @Test
+ public void testInviteAcceptContactNotAssociated() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connect();
+ // send a new invite over the MMTEL feature tag, which is not in the set of feature tags
+ // associated with this delegate.
+ SipDialogAttributes attr = new SipDialogAttributes();
+ attr.addAcceptContactTag(MMTEL_TAG);
+ sendDeniedChatInvite(attr, ifaces,
+ SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG);
+
+ destroySipDelegateAndVerify(ifaces);
+ assertEquals("There should be no more delegates", 0,
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ }
+
+ @Test
+ public void testIncomingInviteDeregistering() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ TransportInterfaces ifaces = new TransportInterfaces(getDefaultRequest(),
+ Collections.emptySet(), 0);
+ ifaces.connect();
+ // move chat to deregistering
+ Set<String> regFeatures = new ArraySet<>(Arrays.asList(DEFAULT_FEATURE_TAGS));
+ regFeatures.remove(ONE_TO_ONE_CHAT_TAG);
+ DelegateRegistrationState state = getDeregisteringState(regFeatures,
+ Collections.singleton(ONE_TO_ONE_CHAT_TAG),
+ DelegateRegistrationState.DEREGISTERING_REASON_PROVISIONING_CHANGE);
+ verifyRegistrationState(ifaces, state);
+ // receive invite, which can not be blocked
+ SipDialogAttributes attr = new SipDialogAttributes();
+ receiveChatInvite(attr, ifaces);
+ // ensure delegate connection can still respond to the request, even if in restricted state.
+ send200OkResponse(attr, ifaces);
+ receiveAck(attr, ifaces);
+ // receive BYE and clean up
+ receiveByeRequest(attr, ifaces);
+ ifaces.delegateConn.sendCleanupSession(attr.callId);
+ ifaces.delegate.verifyCleanupSession(attr.callId);
+
+ destroySipDelegateAndVerify(ifaces);
+ assertEquals("There should be no more delegates", 0,
+ ifaces.transport.getDelegates().size());
+ verifyUpdateRegistrationCalled(ifaces.reg);
+ }
+
private SipMessage generateSipMessage(String str) {
String crlf = "\r\n";
String[] components = str.split(crlf);
@@ -908,6 +1694,82 @@
return index;
}
+ private void sendChatInvite(SipDialogAttributes attr,
+ TransportInterfaces ifaces) throws Exception {
+ SipDialogAttributes invAttr = attr.fromExisting().copyWithNewBranch();
+ invAttr.addAcceptContactTag(ONE_TO_ONE_CHAT_TAG);
+ SipMessage invite = SipMessageUtils.generateSipRequest(SipMessageUtils.INVITE_SIP_METHOD,
+ invAttr);
+ sendMessageAndVerifyAck(invite, ifaces);
+ }
+
+ private void sendDeniedChatInvite(SipDialogAttributes attr,
+ TransportInterfaces ifaces, int denyReason) throws Exception {
+ SipDialogAttributes invAttr = attr.fromExisting().copyWithNewBranch();
+ SipMessage invite = SipMessageUtils.generateSipRequest(SipMessageUtils.INVITE_SIP_METHOD,
+ invAttr);
+ ifaces.delegateConn.sendMessageAndVerifyFailure(invite, denyReason);
+ }
+
+ private void receiveChatInvite(SipDialogAttributes attr,
+ TransportInterfaces ifaces) throws Exception {
+ SipDialogAttributes invAttr = attr.fromExisting().copyWithNewBranch();
+ invAttr.addAcceptContactTag(ONE_TO_ONE_CHAT_TAG);
+ SipMessage invite = SipMessageUtils.generateSipRequest(SipMessageUtils.INVITE_SIP_METHOD,
+ invAttr);
+ receiveMessageAndVerifyAck(invite, ifaces);
+ }
+
+ private void send200OkResponse(SipDialogAttributes attr,
+ TransportInterfaces ifaces) throws Exception {
+ attr.setToTag();
+ // do not update branch here, as it is a response to a request.
+ SipMessage resp = SipMessageUtils.generateSipResponse("200", "OK",
+ attr);
+ sendMessageAndVerifyAck(resp, ifaces);
+ }
+
+ private void receive200OkResponse(SipDialogAttributes attr,
+ TransportInterfaces ifaces) throws Exception {
+ attr.setToTag();
+ // do not update branch here, as it is a response to a request.
+ SipMessage resp = SipMessageUtils.generateSipResponse("200", "OK",
+ attr);
+ receiveMessageAndVerifyAck(resp, ifaces);
+ }
+
+ private void sendAck(SipDialogAttributes attr,
+ TransportInterfaces ifaces) throws Exception {
+ attr = attr.copyWithNewBranch();
+ SipMessage invite = SipMessageUtils.generateSipRequest(SipMessageUtils.ACK_SIP_METHOD,
+ attr);
+ sendMessageAndVerifyAck(invite, ifaces);
+ }
+
+ private void receiveAck(SipDialogAttributes attr,
+ TransportInterfaces ifaces) throws Exception {
+ attr = attr.copyWithNewBranch();
+ SipMessage invite = SipMessageUtils.generateSipRequest(SipMessageUtils.ACK_SIP_METHOD,
+ attr);
+ receiveMessageAndVerifyAck(invite, ifaces);
+ }
+
+ private void sendByeRequest(SipDialogAttributes attr,
+ TransportInterfaces ifaces) throws Exception {
+ attr = attr.copyWithNewBranch();
+ SipMessage invite = SipMessageUtils.generateSipRequest(SipMessageUtils.BYE_SIP_METHOD,
+ attr);
+ sendMessageAndVerifyAck(invite, ifaces);
+ }
+
+ private void receiveByeRequest(SipDialogAttributes attr,
+ TransportInterfaces ifaces) throws Exception {
+ attr = attr.copyWithNewBranch();
+ SipMessage invite = SipMessageUtils.generateSipRequest(SipMessageUtils.BYE_SIP_METHOD,
+ attr);
+ receiveMessageAndVerifyAck(invite, ifaces);
+ }
+
private void createSipDelegateConnectionNoDelegateExpected(SipDelegateManager manager,
TestSipDelegateConnection conn, TestSipTransport transport) throws Exception {
// wait for onCreated and reg state changed
@@ -935,34 +1797,35 @@
SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
}
- private void destroySipDelegateAndVerify(SipDelegateManager manager,
+ private void destroySipDelegate(SipDelegateManager manager,
TestSipTransport transportImpl, TestSipDelegateConnection delegateConn,
- TestSipDelegate delegate, Set<String> registeredTags) throws Exception {
- // wait for registration change upon disconnecting state change
- delegateConn.setOperationCountDownLatch(1);
+ TestSipDelegate delegate) throws Exception {
delegateConn.disconnect(manager,
SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
- delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
- // verify we move to deregistering for registered tags.
- DelegateRegistrationState s = getDeregisteringState(registeredTags,
- DelegateRegistrationState.DEREGISTERING_REASON_DESTROY_PENDING);
- delegateConn.verifyRegistrationStateEquals(s);
- // wait for on destroyed
- delegateConn.setOperationCountDownLatch(1);
transportImpl.waitForLatchCountdownAndReset(TestSipTransport.LATCH_DESTROY_DELEGATE);
delegate.notifyOnDestroyed(
SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+
+ }
+
+ private void destroySipDelegateAndVerifyConnDestroyed(SipDelegateManager manager,
+ TestSipTransport transportImpl, TestSipDelegateConnection delegateConn,
+ TestSipDelegate delegate) throws Exception {
+ delegateConn.setOperationCountDownLatch(1);
+ destroySipDelegate(manager, transportImpl, delegateConn, delegate);
delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
delegateConn.verifyDestroyed(
SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
}
+ private void destroySipDelegateAndVerify(TransportInterfaces ifaces) throws Exception {
+ // wait for on destroyed
+ destroySipDelegateAndVerifyConnDestroyed(ifaces.manager, ifaces.transport,
+ ifaces.delegateConn, ifaces.delegate);
+ }
+
private void verifySipDelegateDestroyed(TestSipTransport transportImpl,
- TestSipDelegateConnection delegateConn, TestSipDelegate delegate,
- Set<String> registeredTags, int deregReason) {
- // verify we move to deregistering for registered tags.
- DelegateRegistrationState s = getDeregisteringState(registeredTags, deregReason);
- delegateConn.verifyRegistrationStateEquals(s);
+ TestSipDelegate delegate) {
transportImpl.waitForLatchCountdownAndReset(TestSipTransport.LATCH_DESTROY_DELEGATE);
delegate.notifyOnDestroyed(
SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
@@ -992,7 +1855,7 @@
private void verifyRegisteredAndSendSipConfig(TestSipDelegateConnection delegateConn,
TestSipDelegate delegate, Set<String> registeredTags,
- Set<FeatureTagState> deniedTags, SipDelegateImsConfiguration sipConfig) {
+ Set<FeatureTagState> deniedTags, SipDelegateConfiguration sipConfig) {
// wait for reg change to be called
delegateConn.setOperationCountDownLatch(1);
DelegateRegistrationState s = getRegisteredRegistrationState(registeredTags);
@@ -1005,6 +1868,25 @@
sendConfigChange(sipConfig, delegateConn, delegate);
}
+ private void verifyRegisteredAndSendOldSipConfig(TestSipDelegateConnection delegateConn,
+ TestSipDelegate delegate, Set<String> registeredTags,
+ Set<FeatureTagState> deniedTags) {
+ // wait for reg change to be called
+ delegateConn.setOperationCountDownLatch(1);
+ DelegateRegistrationState s = getRegisteredRegistrationState(registeredTags);
+ delegate.notifyImsRegistrationUpdate(s);
+ delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ delegateConn.verifyRegistrationStateRegistered(registeredTags);
+ delegateConn.verifyDenied(deniedTags);
+
+ delegateConn.setOperationCountDownLatch(1);
+ // Use the old config here and ensure a equivalent version of the new config is received
+ // by app.
+ delegate.notifyImsConfigurationUpdate(generateOldConfig());
+ delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ delegateConn.verifyConfigEquals(generateNewTestConfig());
+ }
+
private Set<FeatureTagState> generateDeniedSetFromRequest(Set<String> grantedTags,
Set<String> newTags, int reason) {
// Deny features from newTags that are already granted in grantedTags.
@@ -1021,53 +1903,223 @@
ImsUtils.TEST_TIMEOUT_MS));
}
- private void verifyFullRegistrationTriggered(SipDelegateManager manager,
- TestImsRegistration regImpl, TestSipDelegateConnection delegateConn) throws Exception {
- delegateConn.verifyDelegateCreated();
- delegateConn.triggerFullNetworkRegistration(manager, 403, "FORBIDDEN");
+ private void sendRestrictedRequestsAndVerifyFailed(
+ TestSipDelegateConnection delegateConn) throws Exception {
+ delegateConn.sendMessageAndVerifyFailure(SipMessageUtils.TEST_INVALID_SIP_REGISTER,
+ SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_START_LINE);
+ delegateConn.sendMessageAndVerifyFailure(SipMessageUtils.TEST_INVALID_SIP_PUBLISH,
+ SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_START_LINE);
+ delegateConn.sendMessageAndVerifyFailure(SipMessageUtils.TEST_INVALID_SIP_OPTIONS,
+ SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_START_LINE);
+ delegateConn.sendMessageAndVerifyFailure(
+ SipMessageUtils.TEST_INVALID_SIP_SUBSCRIBE_PRESENCE,
+ SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS);
+ }
+
+ private void verifyFullRegistrationTriggered(TransportInterfaces ifaces) throws Exception {
+ ifaces.delegateConn.verifyDelegateCreated();
+ ifaces.delegateConn.triggerFullNetworkRegistration(ifaces.manager, 403, "FORBIDDEN");
TestImsRegistration.NetworkRegistrationInfo info =
- regImpl.getNextFullNetworkRegRequest(ImsUtils.TEST_TIMEOUT_MS);
+ ifaces.reg.getNextFullNetworkRegRequest(ImsUtils.TEST_TIMEOUT_MS);
assertNotNull("full registration requested, but ImsRegistrationImplBase "
+ "implementation did not receive a request.", info);
assertEquals(403, info.sipCode);
assertEquals("FORBIDDEN", info.sipReason);
}
- private void sendMessageAndVerifyAck(TestSipDelegateConnection delegateConn,
+ private void sendInvalidRequestsAndVerifyFailed(
+ TestSipDelegateConnection delegateConn) throws Exception {
+ delegateConn.sendMessageAndVerifyFailure(SipMessageUtils.TEST_SIP_MESSAGE_INVALID_REQUEST,
+ SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_START_LINE);
+ delegateConn.sendMessageAndVerifyFailure(SipMessageUtils.TEST_SIP_MESSAGE_INVALID_RESPONSE,
+ SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_START_LINE);
+ }
+
+ private void verifyOutgoingTransport(TestSipDelegateConnection delegateConn,
TestSipDelegate delegate) throws Exception {
// Send a message and ensure it gets received on the other end as well as acked
- delegateConn.sendMessageAndVerifyCompletedSuccessfully(ImsUtils.TEST_SIP_MESSAGE);
- delegate.verifyMessageSend(ImsUtils.TEST_SIP_MESSAGE);
- delegateConn.sendCloseDialog(ImsUtils.TEST_CALL_ID);
- delegate.verifyCloseDialog(ImsUtils.TEST_CALL_ID);
+ delegateConn.sendMessageAndVerifyCompletedSuccessfully(SipMessageUtils.TEST_SIP_MESSAGE);
+ delegate.verifyMessageSend(SipMessageUtils.TEST_SIP_MESSAGE);
+ delegateConn.sendCleanupSession(SipMessageUtils.TEST_SIP_MESSAGE.getCallIdParameter());
+ delegate.verifyCleanupSession(SipMessageUtils.TEST_SIP_MESSAGE.getCallIdParameter());
// send a message and notify connection that it failed
delegate.setSendMessageDenyReason(
SipDelegateManager.MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE);
- delegateConn.sendMessageAndVerifyFailure(ImsUtils.TEST_SIP_MESSAGE,
+ delegateConn.sendMessageAndVerifyFailure(SipMessageUtils.TEST_SIP_MESSAGE,
SipDelegateManager.MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE);
- delegate.verifyMessageSend(ImsUtils.TEST_SIP_MESSAGE);
+ delegate.verifyMessageSend(SipMessageUtils.TEST_SIP_MESSAGE);
}
- private void receiveMessageAndVerifyAck(TestSipDelegateConnection delegateConn,
+ private void sendMessageAndVerifyAck(SipMessage message,
+ TransportInterfaces ifaces) throws Exception {
+ // Send a message and ensure it gets received on the other end as well as acked
+ ifaces.delegateConn.sendMessageAndVerifyCompletedSuccessfully(message);
+ }
+
+ private void verifyIncomingTransport(TestSipDelegateConnection delegateConn,
TestSipDelegate delegate) throws Exception {
// Receive a message and ensure it gets received on the other end as well as acked
- delegate.receiveMessageAndVerifyReceivedCalled(ImsUtils.TEST_SIP_MESSAGE);
- delegateConn.verifyMessageReceived(ImsUtils.TEST_SIP_MESSAGE);
+ delegate.receiveMessageAndVerifyReceivedCalled(SipMessageUtils.TEST_SIP_MESSAGE);
+ delegateConn.verifyMessageReceived(SipMessageUtils.TEST_SIP_MESSAGE);
// Receive a message and have connection notify that it didn't complete
delegateConn.setReceivedMessageErrorResponseReason(
SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT);
- delegate.receiveMessageAndVerifyReceiveErrorCalled(ImsUtils.TEST_SIP_MESSAGE,
+ delegate.receiveMessageAndVerifyReceiveErrorCalled(SipMessageUtils.TEST_SIP_MESSAGE,
SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT);
}
- private void sendConfigChange(SipDelegateImsConfiguration c,
+ private void receiveMessageAndVerifyAck(SipMessage message,
+ TransportInterfaces ifaces) throws Exception {
+ // Receive a message and ensure it gets received on the other end as well as acked
+ ifaces.delegate.receiveMessageAndVerifyReceivedCalled(message);
+ ifaces.delegateConn.verifyMessageReceived(message);
+ }
+
+ private void verifyRegistrationState(TransportInterfaces ifaces,
+ DelegateRegistrationState state) {
+ ifaces.delegateConn.setOperationCountDownLatch(1);
+ ifaces.delegate.notifyImsRegistrationUpdate(state);
+ ifaces.delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
+ ifaces.delegateConn.verifyRegistrationStateEquals(state);
+ }
+
+ private DelegateRegistrationState getDeregisteringState(Set<String> registered,
+ Set<String> deregistering, int deregisteringReason) {
+ DelegateRegistrationState.Builder b = new DelegateRegistrationState.Builder();
+ b.addRegisteredFeatureTags(registered);
+ for (String dereg : deregistering) {
+ b.addDeregisteringFeatureTag(dereg, deregisteringReason);
+ }
+ return b.build();
+ }
+
+ private void sendConfigChange(SipDelegateConfiguration c,
TestSipDelegateConnection delegateConn, TestSipDelegate delegate) {
delegateConn.setOperationCountDownLatch(1);
- delegate.notifyImsConfigurationUpdate(c);
+ delegate.notifyConfigurationUpdate(c);
delegateConn.waitForCountDown(ImsUtils.TEST_TIMEOUT_MS);
delegateConn.verifyConfigEquals(c);
}
+ /**
+ * @return A new test SipDelegateConfiguration that has all fields populated.1
+ */
+ private SipDelegateConfiguration generateNewTestConfig() {
+ InetSocketAddress localAddr = new InetSocketAddress(
+ InetAddresses.parseNumericAddress("1.1.1.1"), 80);
+ InetSocketAddress serverAddr = new InetSocketAddress(
+ InetAddresses.parseNumericAddress("2.2.2.2"), 81);
+ SipDelegateConfiguration.Builder b = new SipDelegateConfiguration.Builder(1,
+ SipDelegateConfiguration.SIP_TRANSPORT_TCP, localAddr, serverAddr);
+ b.setSipCompactFormEnabled(true);
+ b.setSipKeepaliveEnabled(true);
+ b.setMaxUdpPayloadSizeBytes(508);
+ b.setPublicUserIdentifier("test1");
+ b.setPrivateUserIdentifier("test2");
+ b.setHomeDomain("test.domain");
+ b.setImei("testImei");
+ b.setSipAuthenticationHeader("sipauth");
+ b.setSipAuthenticationNonce("sipnonce");
+ b.setSipServiceRouteHeader("srvroute");
+ b.setSipPathHeader("path");
+ b.setSipUserAgentHeader("ua");
+ b.setSipContactUserParameter("user");
+ b.setSipPaniHeader("pani");
+ b.setSipPlaniHeader("plani");
+ b.setSipCniHeader("cni");
+ b.setSipAssociatedUriHeader("uri");
+ Uri gruuUri = Uri.parse("sip:blah@gruu.net");
+ b.setPublicGruuUri(gruuUri);
+ SipDelegateConfiguration.IpSecConfiguration ipSecConfig =
+ new SipDelegateConfiguration.IpSecConfiguration(123, 124,
+ 125, 126, 127, 128, "secverify");
+ assertEquals(123, ipSecConfig.getLocalTxPort());
+ assertEquals(124, ipSecConfig.getLocalRxPort());
+ assertEquals(125, ipSecConfig.getLastLocalTxPort());
+ assertEquals(126, ipSecConfig.getRemoteTxPort());
+ assertEquals(127, ipSecConfig.getRemoteRxPort());
+ assertEquals(128, ipSecConfig.getLastRemoteTxPort());
+ assertEquals("secverify", ipSecConfig.getSipSecurityVerifyHeader());
+ b.setIpSecConfiguration(ipSecConfig);
+ InetSocketAddress natAddr = new InetSocketAddress(
+ InetAddresses.parseNumericAddress("3.3.3.3"), 129);
+ b.setNatSocketAddress(natAddr);
+ assertEquals("3.3.3.3", natAddr.getAddress().getHostAddress());
+ assertEquals(129, natAddr.getPort());
+ return b.build();
+ }
+
+
+ /**
+ * @return A instance of the deprecated SipDelegateImConfiguration, which has the same
+ * equivalent configuration as {@link #generateNewTestConfig()}.
+ */
+ private SipDelegateImsConfiguration generateOldConfig() {
+ return new SipDelegateImsConfiguration.Builder(1)
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING,
+ SipDelegateImsConfiguration.SIP_TRANSPORT_TCP)
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_DEFAULT_IPADDRESS_STRING,
+ "1.1.1.1")
+ .addInt(SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_DEFAULT_PORT_INT, 80)
+ .addString(SipDelegateImsConfiguration
+ .KEY_SIP_CONFIG_SERVER_DEFAULT_IPADDRESS_STRING,
+ "2.2.2.2")
+ .addInt(SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVER_DEFAULT_PORT_INT, 81)
+ .addBoolean(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_COMPACT_FORM_ENABLED_BOOL,
+ true)
+ .addBoolean(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_KEEPALIVE_ENABLED_BOOL,
+ true)
+ .addInt(SipDelegateImsConfiguration.KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT,
+ 508)
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_PUBLIC_USER_ID_STRING,
+ "test1")
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_PRIVATE_USER_ID_STRING,
+ "test2")
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_HOME_DOMAIN_STRING,
+ "test.domain")
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING, "testImei")
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_AUTHENTICATION_HEADER_STRING,
+ "sipauth")
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_AUTHENTICATION_NONCE_STRING,
+ "sipnonce")
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING,
+ "srvroute")
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_PATH_HEADER_STRING, "path")
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_USER_AGENT_HEADER_STRING,
+ "ua")
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_URI_USER_PART_STRING, "user")
+ .addString(SipDelegateImsConfiguration
+ .KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING, "pani")
+ .addString(SipDelegateImsConfiguration
+ .KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING, "plani")
+ .addString(SipDelegateImsConfiguration
+ .KEY_SIP_CONFIG_CELLULAR_NETWORK_INFO_HEADER_STRING, "cni")
+ .addString(
+ SipDelegateImsConfiguration.KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING,
+ "uri")
+ .addBoolean(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL, true)
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING,
+ "sip:blah@gruu.net")
+ .addBoolean(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL, true)
+ .addInt(SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_IPSEC_CLIENT_PORT_INT, 123)
+ .addInt(SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_IPSEC_SERVER_PORT_INT, 124)
+ .addInt(SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_IPSEC_OLD_CLIENT_PORT_INT,
+ 125)
+ .addInt(SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVER_IPSEC_CLIENT_PORT_INT,
+ 126)
+ .addInt(SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVER_IPSEC_SERVER_PORT_INT,
+ 127)
+ .addInt(SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVER_IPSEC_OLD_CLIENT_PORT_INT,
+ 128)
+ .addString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING,
+ "secverify")
+ .addBoolean(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL, true)
+ .addString(SipDelegateImsConfiguration
+ .KEY_SIP_CONFIG_UE_PUBLIC_IPADDRESS_WITH_NAT_STRING, "3.3.3.3")
+ .addInt(SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_PUBLIC_PORT_WITH_NAT_INT, 129)
+ .build();
+ }
+
private DelegateRegistrationState getRegisteredRegistrationState(Set<String> registered) {
return new DelegateRegistrationState.Builder().addRegisteredFeatureTags(registered).build();
}
@@ -1151,17 +2203,14 @@
}
private DelegateRequest getDefaultRequest() {
- ArraySet<String> features = new ArraySet<>(3);
- features.add(TestSipTransport.ONE_TO_ONE_CHAT_TAG);
- features.add(TestSipTransport.GROUP_CHAT_TAG);
- features.add(TestSipTransport.FILE_TRANSFER_HTTP_TAG);
+ ArraySet<String> features = new ArraySet<>(Arrays.asList(DEFAULT_FEATURE_TAGS));
return new DelegateRequest(features);
}
private DelegateRequest getChatOnlyRequest() {
ArraySet<String> features = new ArraySet<>(3);
- features.add(TestSipTransport.ONE_TO_ONE_CHAT_TAG);
- features.add(TestSipTransport.GROUP_CHAT_TAG);
+ features.add(ONE_TO_ONE_CHAT_TAG);
+ features.add(GROUP_CHAT_TAG);
return new DelegateRequest(features);
}
@@ -1172,12 +2221,18 @@
.addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
.build();
}
+
private ImsFeatureConfiguration getConfigForRcs() {
return new ImsFeatureConfiguration.Builder()
.addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
.build();
}
+ private Set<FeatureTagState> getDeniedTagsForReason(Set<String> deniedTags, int reason) {
+ return deniedTags.stream().map(t -> new FeatureTagState(t, reason))
+ .collect(Collectors.toSet());
+ }
+
private static void overrideCarrierConfig(PersistableBundle bundle) throws Exception {
CarrierConfigManager carrierConfigManager = InstrumentationRegistry.getInstrumentation()
.getContext().getSystemService(CarrierConfigManager.class);
@@ -1187,6 +2242,13 @@
sReceiver.waitForCarrierConfigChanged();
}
+ private static void setFeatureTagsCarrierAllowed(String[] tags) throws Exception {
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putStringArray(CarrierConfigManager.Ims.KEY_RCS_FEATURE_TAG_ALLOWED_STRING_ARRAY,
+ tags);
+ overrideCarrierConfig(bundle);
+ }
+
private SipDelegateManager getSipDelegateManager() {
ImsManager imsManager = getContext().getSystemService(ImsManager.class);
assertNotNull(imsManager);
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/SipDialogAttributes.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/SipDialogAttributes.java
new file mode 100644
index 0000000..dc8e9b2
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/SipDialogAttributes.java
@@ -0,0 +1,133 @@
+/*
+ * 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.telephony.ims.cts;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+import android.net.Uri;
+import android.util.ArraySet;
+import android.util.Base64;
+
+import java.nio.ByteBuffer;
+import java.util.Random;
+import java.util.Set;
+
+public class SipDialogAttributes {
+
+ // Generates sequential string values starting from a random number.
+ private static volatile int sNextStringCounter;
+ static {
+ sNextStringCounter = new Random().nextInt();
+ }
+
+ public final String branchId;
+ public final String callId;
+ public final String fromHeader;
+ public final String fromTag;
+ public final String toUri;
+ public final String toHeader;
+ private final String mFromUri;
+ private final Set<String> mAcceptContactTags;
+ private String mToTag;
+
+ public SipDialogAttributes() {
+ branchId = getNextString();
+ callId = getNextString();
+ mFromUri = getNextSipUri();
+ fromHeader = generateContactUri(mFromUri);
+ fromTag = getNextString();
+ toUri = getNextSipUri();
+ toHeader = generateContactUri(toUri);
+ mAcceptContactTags = new ArraySet<>();
+ }
+
+ private SipDialogAttributes(String branchId, String callId, String fromUri,
+ String fromTag, String toUri, String toTag, Set<String> acceptContactTags) {
+ this.branchId = branchId;
+ this.callId = callId;
+ this.mFromUri = fromUri;
+ this.fromHeader = generateContactUri(fromUri);
+ this.fromTag = fromTag;
+ this.toUri = toUri;
+ this.toHeader = generateContactUri(toUri);
+ mToTag = toTag;
+ mAcceptContactTags = acceptContactTags;
+ }
+
+ public void setToTag() {
+ if (mToTag == null) {
+ mToTag = getNextString();
+ }
+ }
+
+ public String getToTag() {
+ return mToTag;
+ }
+
+ /**
+ * Add a tag to the Accept-Contact header feature tag list.
+ */
+ public void addAcceptContactTag(String featureTag) {
+ mAcceptContactTags.add(featureTag);
+ }
+
+ /**
+ * @return The feature tags in the Accept-Contact feature tag list.
+ */
+ public Set<String> getAcceptContactTags() {
+ return mAcceptContactTags;
+ }
+
+ /**
+ * @return The same attributes with a refreshed via branch param.
+ */
+ public SipDialogAttributes copyWithNewBranch() {
+ return new SipDialogAttributes(branchId, callId, mFromUri, fromTag, toUri,
+ mToTag, mAcceptContactTags);
+ }
+
+ public SipDialogAttributes fromExisting() {
+ return new SipDialogAttributes(branchId, callId, mFromUri, fromTag, toUri,
+ null, mAcceptContactTags);
+ }
+
+ public SipDialogAttributes invertFromTo() {
+ return new SipDialogAttributes(branchId, callId, toUri, fromTag, mFromUri, mToTag,
+ mAcceptContactTags);
+ }
+
+ private String getNextSipUri() {
+ return "sip:" + getNextString() + "@" + SipMessageUtils.BASE_ADDRESS;
+ }
+
+ private String getNextString() {
+ // Get a string representation of the entry counter
+ byte[] idByteArray = ByteBuffer.allocate(4).putInt(sNextStringCounter++).array();
+ return Base64.encodeToString(idByteArray,
+ Base64.NO_WRAP | Base64.NO_PADDING | Base64.URL_SAFE);
+ }
+
+ private String generateContactUri(String sipUri) {
+ Uri uri = Uri.parse(sipUri);
+ assertNotNull(uri);
+ String[] user = uri.getSchemeSpecificPart().split("@", 2);
+ assertNotNull(user);
+ assertEquals(2, user.length);
+ return user[0] + " <" + sipUri + ">";
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/SipMessageParsingTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/SipMessageParsingTest.java
index a260caf..002833d 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/SipMessageParsingTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/SipMessageParsingTest.java
@@ -16,14 +16,14 @@
package android.telephony.ims.cts;
+import static junit.framework.Assert.fail;
+
import static org.junit.Assert.assertEquals;
import android.telephony.ims.SipMessage;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.telephony.SipMessageParsingUtils;
-
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -189,41 +189,43 @@
@Test
public void testGetViaBranch() {
- assertEquals(SIP_MESSAGE_1_TRANSACTION_ID, SipMessageParsingUtils.getTransactionId(
- SIP_MESSAGE_1.getHeaderSection()));
- assertEquals(SIP_MESSAGE_2_TRANSACTION_ID, SipMessageParsingUtils.getTransactionId(
- SIP_MESSAGE_2.getHeaderSection()));
- assertEquals(SIP_MESSAGE_3_TRANSACTION_ID, SipMessageParsingUtils.getTransactionId(
- SIP_MESSAGE_3.getHeaderSection()));
- assertEquals(SIP_MESSAGE_4_TRANSACTION_ID, SipMessageParsingUtils.getTransactionId(
- SIP_MESSAGE_4.getHeaderSection()));
- assertEquals(SIP_MESSAGE_5_TRANSACTION_ID, SipMessageParsingUtils.getTransactionId(
- SIP_MESSAGE_5.getHeaderSection()));
- assertEquals(SIP_MESSAGE_6_TRANSACTION_ID, SipMessageParsingUtils.getTransactionId(
- SIP_MESSAGE_6.getHeaderSection()));
- assertEquals(SIP_MESSAGE_7_TRANSACTION_ID, SipMessageParsingUtils.getTransactionId(
- SIP_MESSAGE_7.getHeaderSection()));
- assertEquals(SIP_MESSAGE_8_TRANSACTION_ID, SipMessageParsingUtils.getTransactionId(
- SIP_MESSAGE_8.getHeaderSection()));
+ assertEquals(SIP_MESSAGE_1_TRANSACTION_ID, SIP_MESSAGE_1.getViaBranchParameter());
+ assertEquals(SIP_MESSAGE_2_TRANSACTION_ID, SIP_MESSAGE_2.getViaBranchParameter());
+ assertEquals(SIP_MESSAGE_3_TRANSACTION_ID, SIP_MESSAGE_3.getViaBranchParameter());
+ assertEquals(SIP_MESSAGE_4_TRANSACTION_ID, SIP_MESSAGE_4.getViaBranchParameter());
+ assertEquals(SIP_MESSAGE_5_TRANSACTION_ID, SIP_MESSAGE_5.getViaBranchParameter());
+ assertEquals(SIP_MESSAGE_6_TRANSACTION_ID, SIP_MESSAGE_6.getViaBranchParameter());
+ assertEquals(SIP_MESSAGE_7_TRANSACTION_ID, SIP_MESSAGE_7.getViaBranchParameter());
+ assertEquals(SIP_MESSAGE_8_TRANSACTION_ID, SIP_MESSAGE_8.getViaBranchParameter());
+
+ try {
+ new SipMessage(
+ "INVITE sip:bob@biloxi.com SIP/2.0",
+ "Max-Forwards: 70\n"
+ + "To: Bob <sip:bob@biloxi.com>\n"
+ + "From: Alice <sip:alice@atlanta.com>;tag=1928301774\n"
+ + "Call-ID: a84b4c76e66710@pc33.atlanta.com\n"
+ + "CSeq: 314159 INVITE\n"
+ + "Contact: <sip:alice@pc33.atlanta.com>\n"
+ + "Content-Type: application/sdp\n"
+ + "Content-Length: 142\n",
+ new byte[0]);
+ fail("A SipMessage must throw an IllegalArgumentException if no Via branch parameter "
+ + "is present in the headers");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
}
@Test
public void testGetCallId() {
- assertEquals(SIP_MESSAGE_1_CALL_ID, SipMessageParsingUtils.getCallId(
- SIP_MESSAGE_1.getHeaderSection()));
- assertEquals(SIP_MESSAGE_2_CALL_ID, SipMessageParsingUtils.getCallId(
- SIP_MESSAGE_2.getHeaderSection()));
- assertEquals(SIP_MESSAGE_3_CALL_ID, SipMessageParsingUtils.getCallId(
- SIP_MESSAGE_3.getHeaderSection()));
- assertEquals(SIP_MESSAGE_4_CALL_ID, SipMessageParsingUtils.getCallId(
- SIP_MESSAGE_4.getHeaderSection()));
- assertEquals(SIP_MESSAGE_5_CALL_ID, SipMessageParsingUtils.getCallId(
- SIP_MESSAGE_5.getHeaderSection()));
- assertEquals(SIP_MESSAGE_6_CALL_ID, SipMessageParsingUtils.getCallId(
- SIP_MESSAGE_6.getHeaderSection()));
- assertEquals(SIP_MESSAGE_7_CALL_ID, SipMessageParsingUtils.getCallId(
- SIP_MESSAGE_7.getHeaderSection()));
- assertEquals(SIP_MESSAGE_8_CALL_ID, SipMessageParsingUtils.getCallId(
- SIP_MESSAGE_8.getHeaderSection()));
+ assertEquals(SIP_MESSAGE_1_CALL_ID, SIP_MESSAGE_1.getCallIdParameter());
+ assertEquals(SIP_MESSAGE_2_CALL_ID, SIP_MESSAGE_2.getCallIdParameter());
+ assertEquals(SIP_MESSAGE_3_CALL_ID, SIP_MESSAGE_3.getCallIdParameter());
+ assertEquals(SIP_MESSAGE_4_CALL_ID, SIP_MESSAGE_4.getCallIdParameter());
+ assertEquals(SIP_MESSAGE_5_CALL_ID, SIP_MESSAGE_5.getCallIdParameter());
+ assertEquals(SIP_MESSAGE_6_CALL_ID, SIP_MESSAGE_6.getCallIdParameter());
+ assertEquals(SIP_MESSAGE_7_CALL_ID, SIP_MESSAGE_7.getCallIdParameter());
+ assertEquals(SIP_MESSAGE_8_CALL_ID, SIP_MESSAGE_8.getCallIdParameter());
}
}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/SipMessageUtils.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/SipMessageUtils.java
new file mode 100644
index 0000000..4ba11603
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/SipMessageUtils.java
@@ -0,0 +1,188 @@
+/*
+ * 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.telephony.ims.cts;
+
+import android.telephony.ims.SipMessage;
+
+import java.util.Set;
+
+
+public class SipMessageUtils {
+
+ public static final String INVITE_SIP_METHOD = "INVITE";
+ public static final String CANCEL_SIP_METHOD = "CANCEL";
+ public static final String BYE_SIP_METHOD = "BYE";
+ public static final String ACK_SIP_METHOD = "ACK";
+ public static final String MESSAGE_SIP_METHOD = "MESSAGE";
+ public static final String BASE_ADDRESS = "client.example.com";
+
+ private static final String PARAM_SEPARATOR = ";";
+ private static final String PARAM_KEY_VALUE_SEPARATOR = "=";
+ private static final String BASE_VIA_HEADER_VALUE = "SIP/2.0/TCP " + BASE_ADDRESS + ":5060";
+
+ public static final SipMessage TEST_SIP_MESSAGE = generateSipRequest(MESSAGE_SIP_METHOD,
+ new SipDialogAttributes());
+
+ // Example from RFC 3665
+ public static final SipMessage TEST_INVALID_SIP_REGISTER = new SipMessage(
+ "REGISTER sips:ss2.biloxi.example.com SIP/2.0",
+ "Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7\n"
+ + "Max-Forwards: 70\n"
+ + "From: Bob <sips:bob@biloxi.example.com>;tag=a73kszlfl\n"
+ + "To: Bob <sips:bob@biloxi.example.com>\n"
+ + "Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com\n"
+ + "CSeq: 1 REGISTER\n"
+ + "Contact: <sips:bob@client.biloxi.example.com>\n"
+ + "Content-Length: 0",
+ new byte[0]);
+
+ //Example from RFC3903, but does not include PIDF document. PUBLISH is not allowed.
+ public static final SipMessage TEST_INVALID_SIP_PUBLISH = new SipMessage(
+ "PUBLISH sip:presentity@example.com SIP/2.0",
+ "Via: SIP/2.0/UDP pua.example.com;branch=z9hG4bKcdad2\n"
+ + "To: <sip:presentity@example.com>\n"
+ + "From: <sip:presentity@example.com>;tag=54321mm\n"
+ + "Call-ID: 5566778@pua.example.com\n"
+ + "CSeq: 1 PUBLISH\n"
+ + "Max-Forwards: 70\n"
+ + "Expires: 3600\n"
+ + "Event: presence\n"
+ + "Content-Type: application/pidf+xml",
+ new byte[0]);
+
+ //Example from RFC3856 - SUBSCRIBE with event presence is not allowed
+ public static final SipMessage TEST_INVALID_SIP_SUBSCRIBE_PRESENCE = new SipMessage(
+ "SUBSCRIBE sip:resource@example.com SIP/2.0",
+ "Via: SIP/2.0/TCP watcherhost.example.com;branch=z9hG4bKnashds7\n"
+ + "To: <sip:resource@example.com>\n"
+ + "From: <sip:user@example.com>;tag=xfg9\n"
+ + "Call-ID: 2010@watcherhost.example.com\n"
+ + "CSeq: 17766 SUBSCRIBE\n"
+ + "Max-Forwards: 70\n"
+ + "Event: presence\n"
+ + "Accept: application/pidf+xml\n"
+ + "Contact: <sip:user@watcherhost.example.com>\n"
+ + "Expires: 600\n"
+ + "Content-Length: 0",
+ new byte[0]);
+
+ //Example from RFC3261, OPTIONS not allowed from app
+ public static final SipMessage TEST_INVALID_SIP_OPTIONS = new SipMessage(
+ "OPTIONS sip:carol@chicago.com SIP/2.0",
+ "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKhjhs8ass877\n"
+ + "Max-Forwards: 70\n"
+ + "To: <sip:carol@chicago.com>\n"
+ + "From: Alice <sip:alice@atlanta.com>;tag=1928301774\n"
+ + "Call-ID: a84b4c76e66710\n"
+ + "CSeq: 63104 OPTIONS\n"
+ + "Contact: <sip:alice@pc33.atlanta.com>\n"
+ + "Accept: application/sdp\n"
+ + "Content-Length: 0",
+ new byte[0]);
+
+ // Sample message from RFC 3261, malformed request start line
+ public static final SipMessage TEST_SIP_MESSAGE_INVALID_REQUEST = new SipMessage(
+ "INVITE sip:bob@biloxi.comSIP/2.0",
+ // Typical Via
+ "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK.TeSt\n"
+ + "Max-Forwards: 70\n"
+ + "To: Bob <sip:bob@biloxi.com>\n"
+ + "From: Alice <sip:alice@atlanta.com>;tag=1928301774\n"
+ + "Call-ID: a84b4c76e66710@pc33.atlanta.com\n"
+ + "CSeq: 314159 INVITE\n"
+ + "Contact: <sip:alice@pc33.atlanta.com>\n"
+ + "Content-Type: application/sdp\n"
+ + "Content-Length: 142",
+ new byte[0]);
+
+ // Sample message from RFC 3261, malformed response start line
+ public static final SipMessage TEST_SIP_MESSAGE_INVALID_RESPONSE = new SipMessage(
+ "SIP/2.0 200OK",
+ "Via: SIP/2.0/TCP terminal.vancouver.example.com;"
+ + "branch=z9hG4bKwYb6QREiCL\n"
+ + "To: <sip:adam-buddies@pres.vancouver.example.com>;tag=zpNctbZq\n"
+ + "From: <sip:adam@vancouver.example.com>;tag=ie4hbb8t\n"
+ + "Call-ID: cdB34qLToC@terminal.vancouver.example.com\n"
+ + "CSeq: 322723822 SUBSCRIBE\n"
+ + "Contact: <sip:pres.vancouver.example.com>\n"
+ + "Expires: 7200\n"
+ + "Require: eventlist\n"
+ + "Content-Length: 0",
+ new byte[0]);
+
+ /**
+ * @return A new SIP request from the given parameters.
+ */
+ public static SipMessage generateSipRequest(String requestMethod, String fromContact,
+ String toContact, String toUri, String branchId, String callId, String fromTag,
+ String toTag, Set<String> acceptContactTags) {
+ String header = "Via: " + addParamToHeader(BASE_VIA_HEADER_VALUE, "branch", branchId);
+ header += "\n";
+ header += "From: " + addParamToHeader(fromContact, "tag", fromTag);
+ header += "\n";
+ // To tag is optional
+ header += "To: " + ((toTag != null)
+ ? addParamToHeader(toContact, "tag", toTag) : toContact);
+ header += "\n";
+ header += "Call-ID: " + callId;
+ if (!acceptContactTags.isEmpty()) {
+ header += "\n";
+ header += "Accept-Contact: *";
+ for (String tag : acceptContactTags) {
+ header += ";" + tag;
+ }
+ }
+ return new SipMessage(requestMethod + " " + toUri + " SIP/2.0", header, new byte[0]);
+ }
+
+ /**
+ * @return Generates a SIP response.
+ */
+ public static SipMessage generateSipResponse(String statusCode, String statusString,
+ String fromContact, String toContact, String branchId, String callId, String fromTag,
+ String toTag) {
+ String header = "Via: " + addParamToHeader(BASE_VIA_HEADER_VALUE, "branch", branchId);
+ header += "\n";
+ header += "From: " + addParamToHeader(fromContact, "tag", fromTag);
+ header += "\n";
+ // To tag is optional
+ header += "To: " + ((toTag != null)
+ ? addParamToHeader(toContact, "tag", toTag) : toContact);
+ header += "\n";
+ header += "Call-ID: " + callId;
+ return new SipMessage("SIP/2.0 " + statusCode + " " + statusString, header,
+ new byte[0]);
+ }
+
+ public static SipMessage generateSipRequest(String requestMethod, SipDialogAttributes attr) {
+ return generateSipRequest(requestMethod, attr.fromHeader, attr.toHeader,
+ attr.toUri, attr.branchId, attr.callId, attr.fromTag, attr.getToTag(),
+ attr.getAcceptContactTags());
+ }
+
+ public static SipMessage generateSipResponse(String statusCode, String statusString,
+ SipDialogAttributes attr) {
+ return generateSipResponse(statusCode, statusString, attr.fromHeader,
+ attr.toHeader, attr.branchId, attr.callId, attr.fromTag, attr.getToTag());
+ }
+
+ private static String addParamToHeader(String headerValue, String paramKey, String paramValue) {
+ headerValue += PARAM_SEPARATOR + paramKey.trim() + PARAM_KEY_VALUE_SEPARATOR
+ + paramValue.trim();
+ return headerValue;
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestAcsClient.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestAcsClient.java
index 1cdf186..513ce83 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestAcsClient.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestAcsClient.java
@@ -17,6 +17,7 @@
package android.telephony.ims.cts;
import android.telephony.ims.RcsClientConfiguration;
+import android.telephony.ims.stub.ImsConfigImplBase;
import java.util.concurrent.LinkedBlockingQueue;
@@ -29,6 +30,7 @@
private LinkedBlockingQueue<Integer> mActionQueue = new LinkedBlockingQueue<>();
private RcsClientConfiguration mRcc;
private byte[] mConfig;
+ private ImsConfigImplBase mImsConfigImpl;
private static TestAcsClient sInstance;
@@ -77,4 +79,12 @@
mRcc = null;
mConfig = null;
}
+
+ public void setImsConfigImpl(ImsConfigImplBase impl) {
+ mImsConfigImpl = impl;
+ }
+
+ public void notifyPreProvisioning(byte[] conf) {
+ mImsConfigImpl.notifyPreProvisioningReceived(conf);
+ }
}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsConfig.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsConfig.java
index 22af8e4..10a39d3 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsConfig.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsConfig.java
@@ -26,6 +26,10 @@
private HashMap<Integer, Integer> mIntHashMap = new HashMap<>();
private HashMap<Integer, String> mStringHashMap = new HashMap<>();
+ TestImsConfig() {
+ TestAcsClient.getInstance().setImsConfigImpl(this);
+ }
+
@Override
public int setConfig(int item, int value) {
mIntHashMap.put(item, value);
@@ -56,16 +60,19 @@
@Override
public void notifyRcsAutoConfigurationRemoved() {
+ super.notifyRcsAutoConfigurationRemoved();
TestAcsClient.getInstance().onConfigRemoved();
}
@Override
public void setRcsClientConfiguration(RcsClientConfiguration rcc) {
+ super.setRcsClientConfiguration(rcc);
TestAcsClient.getInstance().onSetRcsClientConfiguration(rcc);
}
@Override
public void triggerAutoConfiguration() {
+ super.triggerAutoConfiguration();
TestAcsClient.getInstance().onTriggerAutoConfiguration();
}
}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
index 912d95c..a012513 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
@@ -88,7 +88,7 @@
interface CapabilitiesSetListener {
void onSet();
}
- interface RcsCapabilitySetListener {
+ interface RcsCapabilityExchangeEventListener {
void onSet();
}
interface DeviceCapPublishListener {
@@ -148,7 +148,7 @@
public RcsFeature createRcsFeature(int slotId) {
synchronized (mLock) {
countDownLatch(LATCH_CREATE_RCS);
- mTestRcsFeature = new TestRcsFeature(
+ mTestRcsFeature = new TestRcsFeature(getBaseContext(),
//onReady
() -> {
synchronized (mLock) {
@@ -345,6 +345,23 @@
return complete;
}
+ public boolean waitForLatchCountdown(int latchIndex, long waitMs) {
+ boolean complete = false;
+ try {
+ CountDownLatch latch;
+ synchronized (mLock) {
+ latch = sLatches[latchIndex];
+ }
+ complete = latch.await(waitMs, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ // complete == false
+ }
+ synchronized (mLock) {
+ sLatches[latchIndex] = new CountDownLatch(1);
+ }
+ return complete;
+ }
+
public void countDownLatch(int latchIndex) {
synchronized (mLock) {
sLatches[latchIndex].countDown();
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsCapabilityExchangeImpl.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsCapabilityExchangeImpl.java
index 99639a3..c41e63e 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsCapabilityExchangeImpl.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsCapabilityExchangeImpl.java
@@ -22,8 +22,8 @@
import android.telephony.ims.stub.RcsCapabilityExchangeImplBase;
import android.util.Log;
-import java.util.List;
-import java.util.concurrent.Executor;
+import java.util.Collection;
+import java.util.Set;
/**
* A implementation class of RcsCapabilityExchangeImplBase for the TestRcsFeature.
@@ -40,12 +40,12 @@
@FunctionalInterface
public interface SubscribeOperation {
- void execute(List<Uri> uris, SubscribeResponseCallback cb) throws ImsException;
+ void execute(Collection<Uri> uris, SubscribeResponseCallback cb) throws ImsException;
}
@FunctionalInterface
public interface OptionsOperation {
- void execute(Uri contactUri, List<String> myCapabilities, OptionsResponseCallback callback)
+ void execute(Uri contactUri, Set<String> myCapabilities, OptionsResponseCallback callback)
throws ImsException;
}
@@ -62,10 +62,8 @@
/**
* Create a new RcsCapabilityExchangeImplBase instance.
- * @param executor The executor that remote calls from the framework will be called on.
*/
- public TestRcsCapabilityExchangeImpl(Executor executor, DeviceCapPublishListener listener) {
- super(executor);
+ public TestRcsCapabilityExchangeImpl(DeviceCapPublishListener listener) {
mPublishListener = listener;
}
@@ -91,7 +89,7 @@
}
@Override
- public void subscribeForCapabilities(List<Uri> uris, SubscribeResponseCallback cb) {
+ public void subscribeForCapabilities(Collection<Uri> uris, SubscribeResponseCallback cb) {
try {
mSubscribeOperation.execute(uris, cb);
} catch (ImsException e) {
@@ -100,7 +98,7 @@
}
@Override
- public void sendOptionsCapabilityRequest(Uri contactUri, List<String> myCapabilities,
+ public void sendOptionsCapabilityRequest(Uri contactUri, Set<String> myCapabilities,
OptionsResponseCallback callback) {
try {
mOptionsOperation.execute(contactUri, myCapabilities, callback);
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java
index 593e61e..08eaa85 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java
@@ -16,16 +16,15 @@
package android.telephony.ims.cts;
+import android.content.Context;
import android.telephony.ims.feature.CapabilityChangeRequest;
-import android.telephony.ims.feature.CapabilityChangeRequest.CapabilityPair;
-import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.RcsFeature;
import android.telephony.ims.stub.CapabilityExchangeEventListener;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.telephony.ims.stub.RcsCapabilityExchangeImplBase;
import android.util.Log;
import java.util.List;
-import java.util.Optional;
import java.util.concurrent.Executor;
public class TestRcsFeature extends RcsFeature {
@@ -34,24 +33,30 @@
private final TestImsService.ReadyListener mReadyListener;
private final TestImsService.RemovedListener mRemovedListener;
- private final TestImsService.CapabilitiesSetListener mCapSetListener;
- private final TestImsService.RcsCapabilitySetListener mRcsCapabilitySetListener;
+ private final TestImsService.RcsCapabilityExchangeEventListener mCapExchangeEventListener;
+
+ private final RcsImsCapabilities mRcsCapabilitiesLte;
+ private final RcsImsCapabilities mRcsCapabilitiesIWan;
+ private final TestImsService.CapabilitiesSetListener mRcsCapabilityChangedListener;
private TestRcsCapabilityExchangeImpl mCapExchangeImpl;
private CapabilityExchangeEventListener mCapEventListener;
private TestImsService.DeviceCapPublishListener mDeviceCapPublishListener;
- private CapabilityChangeRequest mCapabilityChangeRequest;
- private int mCapabilitiesChangedResult = ImsFeature.CAPABILITY_SUCCESS;
-
- TestRcsFeature(TestImsService.ReadyListener readyListener,
- TestImsService.RemovedListener listener,
+ TestRcsFeature(Context context,
+ TestImsService.ReadyListener readyListener,
+ TestImsService.RemovedListener removedListener,
TestImsService.CapabilitiesSetListener setListener,
- TestImsService.RcsCapabilitySetListener uceCallbackListener) {
+ TestImsService.RcsCapabilityExchangeEventListener capExchangeEventListener) {
+ super(context.getMainExecutor());
+
mReadyListener = readyListener;
- mRemovedListener = listener;
- mCapSetListener = setListener;
- mRcsCapabilitySetListener = uceCallbackListener;
+ mRemovedListener = removedListener;
+ mCapExchangeEventListener = capExchangeEventListener;
+
+ mRcsCapabilityChangedListener = setListener;
+ mRcsCapabilitiesLte = new RcsImsCapabilities(RcsImsCapabilities.CAPABILITY_TYPE_NONE);
+ mRcsCapabilitiesIWan = new RcsImsCapabilities(RcsImsCapabilities.CAPABILITY_TYPE_NONE);
setFeatureState(STATE_READY);
}
@@ -60,10 +65,6 @@
mDeviceCapPublishListener = listener;
}
- public void overrideCapabilitiesEnabledResult(int result) {
- mCapabilitiesChangedResult = result;
- }
-
@Override
public void onFeatureReady() {
if (ImsUtils.VDBG) {
@@ -82,20 +83,28 @@
public RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(Executor executor,
CapabilityExchangeEventListener listener) {
+ return createCapabilityExchangeImpl(listener);
+ }
+
+ @Override
+ public RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(
+ CapabilityExchangeEventListener listener) {
if (ImsUtils.VDBG) {
Log.d(TAG, "TestRcsFeature.createCapabilityExchangeImpl called");
}
mCapEventListener = listener;
- mCapExchangeImpl = new TestRcsCapabilityExchangeImpl(executor, mDeviceCapPublishListener);
- mRcsCapabilitySetListener.onSet();
+ mCapExchangeImpl = new TestRcsCapabilityExchangeImpl(mDeviceCapPublishListener);
+ mCapExchangeEventListener.onSet();
return mCapExchangeImpl;
}
- public void removeCapabilityExchangeImpl(RcsCapabilityExchangeImplBase capExchangeImpl) {
+ @Override
+ public void destroyCapabilityExchangeImpl(RcsCapabilityExchangeImplBase capExchangeImpl) {
if (ImsUtils.VDBG) {
- Log.d(TAG, "TestRcsFeature.removeCapabilityExchangeImpl called");
+ Log.d(TAG, "TestRcsFeature.destroyCapabilityExchangeImpl called");
}
- mRcsCapabilitySetListener.onSet();
+ mCapEventListener = null;
+ mCapExchangeEventListener.onSet();
}
public CapabilityExchangeEventListener getEventListener() {
@@ -109,26 +118,39 @@
@Override
public void changeEnabledCapabilities(CapabilityChangeRequest request,
CapabilityCallbackProxy c) {
- // Trigger the error callback if the result is failed
- if (mCapabilitiesChangedResult != ImsFeature.CAPABILITY_SUCCESS) {
- CapabilityChangeRequest.CapabilityPair capPair = request.getCapabilitiesToEnable()
- .get(0);
- c.onChangeCapabilityConfigurationError(capPair.getCapability(), capPair.getRadioTech(),
- ImsFeature.CAPABILITY_ERROR_GENERIC);
- return;
+
+ // Enabled RCS capabilities
+ List<CapabilityChangeRequest.CapabilityPair> pairs = request.getCapabilitiesToEnable();
+ for (CapabilityChangeRequest.CapabilityPair pair : pairs) {
+ if (pair.getRadioTech() == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+ mRcsCapabilitiesLte.addCapabilities(pair.getCapability());
+ } else if (pair.getRadioTech() == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN) {
+ mRcsCapabilitiesIWan.addCapabilities(pair.getCapability());
+ }
}
- mCapabilityChangeRequest = request;
- // Notify that the capabilities is changed.
- mCapSetListener.onSet();
+
+ // Disabled RCS capabilities
+ pairs = request.getCapabilitiesToDisable();
+ for (CapabilityChangeRequest.CapabilityPair pair : pairs) {
+ if (pair.getRadioTech() == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+ mRcsCapabilitiesLte.removeCapabilities(pair.getCapability());
+ } else if (pair.getRadioTech() == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN) {
+ mRcsCapabilitiesIWan.removeCapabilities(pair.getCapability());
+ }
+ }
+ mRcsCapabilityChangedListener.onSet();
}
@Override
public boolean queryCapabilityConfiguration(int capability, int radioTech) {
- List<CapabilityPair> pairList = mCapabilityChangeRequest.getCapabilitiesToEnable();
- if (pairList == null) return false;
- Optional<CapabilityPair> queryResult = pairList.stream().filter(pair -> {
- return (pair.getCapability() == capability) && (pair.getRadioTech() == radioTech);
- }).findAny();
- return queryResult.isPresent();
+ if (ImsUtils.VDBG) {
+ Log.d(TAG, "TestRcsFeature.queryCapabilityConfiguration capability: " + capability);
+ }
+ if (radioTech == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+ return mRcsCapabilitiesLte.isCapable(capability);
+ } else if (radioTech == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN) {
+ return mRcsCapabilitiesIWan.isCapable(capability);
+ }
+ return false;
}
}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipDelegate.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipDelegate.java
index 729efb9..5040dcf 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipDelegate.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipDelegate.java
@@ -16,6 +16,8 @@
package android.telephony.ims.cts;
+import static junit.framework.Assert.assertTrue;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -24,9 +26,11 @@
import android.telephony.ims.DelegateRequest;
import android.telephony.ims.DelegateStateCallback;
import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.SipDelegateConfiguration;
import android.telephony.ims.SipDelegateImsConfiguration;
import android.telephony.ims.SipMessage;
import android.telephony.ims.stub.SipDelegate;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
@@ -48,7 +52,8 @@
// Pair is <transactionId, error reason>
private final LinkedBlockingQueue<Pair<String, Integer>> mReceivedMessageAcks =
new LinkedBlockingQueue<>();
- private final LinkedBlockingQueue<String> mCloseDialogRequests = new LinkedBlockingQueue<>();
+ private final LinkedBlockingQueue<String> mCleanupSipSessionRequests =
+ new LinkedBlockingQueue<>();
private int mSendMessageDenyReason = -1;
public TestSipDelegate(int sub, DelegateRequest request, DelegateStateCallback cb,
@@ -64,17 +69,17 @@
if (ImsUtils.VDBG) Log.d(LOG_TAG, "sendMessage");
mIncomingMessages.offer(message);
if (mSendMessageDenyReason > -1) {
- mMessageCallback.onMessageSendFailure(ImsUtils.TEST_TRANSACTION_ID,
+ mMessageCallback.onMessageSendFailure(message.getViaBranchParameter(),
mSendMessageDenyReason);
} else {
- mMessageCallback.onMessageSent(ImsUtils.TEST_TRANSACTION_ID);
+ mMessageCallback.onMessageSent(message.getViaBranchParameter());
}
}
@Override
- public void closeDialog(@NonNull String callId) {
- if (ImsUtils.VDBG) Log.d(LOG_TAG, "closeDialog");
- mCloseDialogRequests.offer(callId);
+ public void cleanupSession(@NonNull String callId) {
+ if (ImsUtils.VDBG) Log.d(LOG_TAG, "CleanSession");
+ mCleanupSipSessionRequests.offer(callId);
}
@Override
@@ -94,10 +99,15 @@
assertEquals(messageToVerify, m);
}
- public void verifyCloseDialog(String callIdToVerify) throws Exception {
- String requestedCallId = mCloseDialogRequests.poll(ImsUtils.TEST_TIMEOUT_MS,
- TimeUnit.MILLISECONDS);
- assertEquals(callIdToVerify, requestedCallId);
+ public void verifyCleanupSession(String... callIdsToVerify) throws Exception {
+ Set<String> ids = new ArraySet<>(callIdsToVerify);
+ for (int i = 0; i < callIdsToVerify.length; i++) {
+ String requestedCallId = mCleanupSipSessionRequests.poll(ImsUtils.TEST_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS);
+ assertTrue(ids.contains(requestedCallId));
+ ids.remove(requestedCallId);
+ }
+ assertTrue(ids.isEmpty());
}
public void setSendMessageDenyReason(int reason) {
@@ -108,7 +118,7 @@
mMessageCallback.onMessageReceived(m);
Pair<String, Integer> transactionAndIdPair = mReceivedMessageAcks.poll(
ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- assertEquals(ImsUtils.TEST_TRANSACTION_ID, transactionAndIdPair.first);
+ assertEquals(m.getViaBranchParameter(), transactionAndIdPair.first);
assertNotNull(transactionAndIdPair.second);
assertEquals(-1, transactionAndIdPair.second.intValue());
}
@@ -118,7 +128,7 @@
mMessageCallback.onMessageReceived(m);
Pair<String, Integer> transactionAndIdPair = mReceivedMessageAcks.poll(
ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- assertEquals(ImsUtils.TEST_TRANSACTION_ID, transactionAndIdPair.first);
+ assertEquals(m.getViaBranchParameter(), transactionAndIdPair.first);
assertNotNull(transactionAndIdPair.second);
assertEquals(reason, transactionAndIdPair.second.intValue());
}
@@ -127,6 +137,10 @@
mStateCallback.onFeatureTagRegistrationChanged(state);
}
+ public void notifyConfigurationUpdate(SipDelegateConfiguration config) {
+ mStateCallback.onConfigurationChanged(config);
+ }
+
public void notifyImsConfigurationUpdate(SipDelegateImsConfiguration config) {
mStateCallback.onImsConfigurationChanged(config);
}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipDelegateConnection.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipDelegateConnection.java
index 1118009..dfa8066 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipDelegateConnection.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipDelegateConnection.java
@@ -23,13 +23,12 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
-import android.os.PersistableBundle;
import android.telephony.ims.DelegateRegistrationState;
import android.telephony.ims.DelegateRequest;
import android.telephony.ims.FeatureTagState;
import android.telephony.ims.ImsException;
+import android.telephony.ims.SipDelegateConfiguration;
import android.telephony.ims.SipDelegateConnection;
-import android.telephony.ims.SipDelegateImsConfiguration;
import android.telephony.ims.SipDelegateManager;
import android.telephony.ims.SipMessage;
import android.telephony.ims.stub.DelegateConnectionMessageCallback;
@@ -61,7 +60,7 @@
public SipDelegateConnection connection;
public Set<FeatureTagState> deniedTags;
public DelegateRegistrationState regState;
- public SipDelegateImsConfiguration sipConfig;
+ public SipDelegateConfiguration sipConfig;
public final DelegateRequest delegateRequest;
private int mReceivedMessageErrorResponseReason = -1;
@@ -103,10 +102,10 @@
if (ImsUtils.VDBG) Log.d(LOG_TAG, "onMessageReceived");
mReceivedMessages.offer(message);
if (mReceivedMessageErrorResponseReason > -1) {
- connection.notifyMessageReceiveError(ImsUtils.TEST_TRANSACTION_ID,
+ connection.notifyMessageReceiveError(message.getViaBranchParameter(),
mReceivedMessageErrorResponseReason);
} else {
- connection.notifyMessageReceived(ImsUtils.TEST_TRANSACTION_ID);
+ connection.notifyMessageReceived(message.getViaBranchParameter());
}
}
@@ -139,9 +138,9 @@
}
@Override
- public void onImsConfigurationChanged(
- @NonNull SipDelegateImsConfiguration registeredSipConfig) {
- if (ImsUtils.VDBG) Log.d(LOG_TAG, "onImsConfigurationChanged");
+ public void onConfigurationChanged(
+ @NonNull SipDelegateConfiguration registeredSipConfig) {
+ if (ImsUtils.VDBG) Log.d(LOG_TAG, "onConfigurationChanged");
sipConfig = registeredSipConfig;
mLatch.countDown();
}
@@ -154,9 +153,9 @@
mLatch.countDown();
}
- public void sendCloseDialog(String callId) {
- assertNotNull("SipDelegate was null when closing dialog", connection);
- connection.closeDialog(callId);
+ public void sendCleanupSession(String callId) {
+ assertNotNull("SipDelegate was null when cleaning up session", connection);
+ connection.cleanupSession(callId);
}
public void sendMessageAndVerifyCompletedSuccessfully(SipMessage messageToSend)
@@ -166,7 +165,7 @@
Pair<String, Integer> ack = mSentMessageAcks.poll(ImsUtils.TEST_TIMEOUT_MS,
TimeUnit.MILLISECONDS);
assertNotNull(ack);
- assertEquals(ImsUtils.TEST_TRANSACTION_ID, ack.first);
+ assertEquals(messageToSend.getViaBranchParameter(), ack.first);
assertNotNull(ack.second);
assertEquals(-1, ack.second.intValue());
}
@@ -201,20 +200,11 @@
assertNotNull("SipDelegate is null when it should have been created", connection);
}
- public void verifyConfigEquals(SipDelegateImsConfiguration config) {
+ public void verifyConfigEquals(SipDelegateConfiguration config) {
assertNotNull("SIP configuration should not be null", sipConfig);
assertEquals("IMS config version is not correct", config.getVersion(),
sipConfig.getVersion());
- PersistableBundle b = config.copyBundle();
- for (String key : b.keySet()) {
- assertTrue("tracked sip config does not contain the key [" + key + "}",
- sipConfig.containsKey(key));
- // Not a true equality check, but close enough for the purposes of this test.
- assertEquals(config.getString(key), sipConfig.getString(key));
- assertEquals(config.getInt(key, -1), sipConfig.getInt(key, -1));
- assertEquals(config.getBoolean(key, false),
- sipConfig.getBoolean(key, false));
- }
+ assertEquals(config, sipConfig);
}
public void verifyRegistrationStateRegistered() {
@@ -249,6 +239,15 @@
regState.getDeregisteredFeatureTags());
}
+ public boolean verifyDeregisteringStateContains(String featureTag, int state) {
+ for (FeatureTagState s : regState.getDeregisteringFeatureTags()) {
+ if (s.getFeatureTag().equals(featureTag) && s.getState() == state) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public void verifyNoneDenied() {
assertNotNull(deniedTags);
@@ -287,6 +286,7 @@
* to wait for the operations to occur.
*/
public void setOperationCountDownLatch(int operationCount) {
+ if (ImsUtils.VDBG) Log.d(LOG_TAG, "setOperationCountDownLatch: " + operationCount);
mLatch = new CountDownLatch(operationCount);
}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipTransport.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipTransport.java
index ed5a07b..0ea195c 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipTransport.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestSipTransport.java
@@ -93,6 +93,14 @@
}
}
+ public boolean isLatchCountDownFinished(int latchIndex) {
+ CountDownLatch latch;
+ synchronized (mLock) {
+ latch = sLatches[latchIndex];
+ }
+ return latch.getCount() <= 0;
+ }
+
public boolean waitForLatchCountdownAndReset(int latchIndex) {
boolean complete = false;
try {
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/UceActivity.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/UceActivity.java
deleted file mode 100644
index 5b631ec..0000000
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/UceActivity.java
+++ /dev/null
@@ -1,66 +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.telephony.ims.cts;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.SurfaceView;
-import android.view.ViewGroup;
-
-import java.util.concurrent.CountDownLatch;
-
-/**
- * The Activity to run the UCE APIs verification in the foreground.
- */
-public class UceActivity extends Activity {
-
- public static final String ACTION_FINISH = "android.telephony.ims.cts.action_finish";
-
- private static CountDownLatch sCountDownLatch;
-
- public static void setCountDownLatch(CountDownLatch countDownLatch) {
- sCountDownLatch = countDownLatch;
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- SurfaceView mSurfaceView = new SurfaceView(this);
- mSurfaceView.setWillNotDraw(false);
- mSurfaceView.setZOrderOnTop(true);
- setContentView(mSurfaceView,
- new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- if (sCountDownLatch != null) {
- sCountDownLatch.countDown();
- }
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- if (ACTION_FINISH.equals(intent.getAction())) {
- finish();
- sCountDownLatch = null;
- }
- }
-}
diff --git a/tests/tests/telephony/sdk28/src/android/telephony/sdk28/cts/CellInfoTest.java b/tests/tests/telephony/sdk28/src/android/telephony/sdk28/cts/CellInfoTest.java
index dc590b8..e9b7f16 100644
--- a/tests/tests/telephony/sdk28/src/android/telephony/sdk28/cts/CellInfoTest.java
+++ b/tests/tests/telephony/sdk28/src/android/telephony/sdk28/cts/CellInfoTest.java
@@ -30,6 +30,8 @@
import android.telephony.TelephonyManager;
import android.util.Log;
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
import org.junit.Before;
import org.junit.Test;
@@ -49,7 +51,9 @@
private PackageManager mPm;
private boolean isCamped() {
- ServiceState ss = mTm.getServiceState();
+ ServiceState ss = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTm, TelephonyManager::getServiceState);
+
if (ss == null) return false;
return (ss.getState() == ServiceState.STATE_IN_SERVICE
|| ss.getState() == ServiceState.STATE_EMERGENCY_ONLY);
@@ -76,7 +80,8 @@
if (!isCamped()) fail("Device is not camped to a cell");
- List<CellInfo> cellInfo = mTm.getAllCellInfo();
+ List<CellInfo> cellInfo = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTm, TelephonyManager::getAllCellInfo);
// getAllCellInfo should never return null, and there should be at least one entry.
assertNotNull("TelephonyManager.getAllCellInfo() returned NULL CellInfo", cellInfo);
@@ -90,7 +95,8 @@
} catch (InterruptedException ie) {
fail("Thread was interrupted");
}
- List<CellInfo> newCellInfo = mTm.getAllCellInfo();
+ List<CellInfo> newCellInfo = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTm, TelephonyManager::getAllCellInfo);
assertNotNull("TelephonyManager.getAllCellInfo() returned NULL CellInfo", newCellInfo);
assertFalse("TelephonyManager.getAllCellInfo() returned an empty list",
newCellInfo.isEmpty());
diff --git a/tests/tests/telephonyprovider/AndroidManifest.xml b/tests/tests/telephonyprovider/AndroidManifest.xml
index 9a9e618..4adb19a 100755
--- a/tests/tests/telephonyprovider/AndroidManifest.xml
+++ b/tests/tests/telephonyprovider/AndroidManifest.xml
@@ -19,10 +19,11 @@
package="android.telephonyprovider.cts"
android:targetSandboxVersion="2">
- <uses-permission android:name="android.permission.READ_SMS" />
- <uses-permission android:name="android.permission.SEND_SMS" />
- <uses-permission android:name="android.permission.RECEIVE_SMS" />
- <uses-permission android:name="android.permission.RECEIVE_MMS" />
+ <uses-permission android:name="android.permission.READ_SMS"/>
+ <uses-permission android:name="android.permission.SEND_SMS"/>
+ <uses-permission android:name="android.permission.RECEIVE_SMS"/>
+ <uses-permission android:name="android.permission.RECEIVE_MMS"/>
+ <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<application>
<uses-library android:name="android.test.runner" />
diff --git a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/ServiceStateTest.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/ServiceStateTest.java
new file mode 100644
index 0000000..09e4735
--- /dev/null
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/ServiceStateTest.java
@@ -0,0 +1,398 @@
+/*
+ * 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.telephonyprovider.cts;
+
+import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
+import static android.provider.Telephony.ServiceStateTable.DATA_NETWORK_TYPE;
+import static android.provider.Telephony.ServiceStateTable.DATA_REG_STATE;
+import static android.provider.Telephony.ServiceStateTable.DUPLEX_MODE;
+import static android.provider.Telephony.ServiceStateTable.VOICE_REG_STATE;
+import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.Manifest;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Parcel;
+import android.provider.Telephony;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.NetworkRegistrationInfo;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import androidx.annotation.Nullable;
+import androidx.test.filters.SmallTest;
+
+import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+@SmallTest
+public class ServiceStateTest {
+
+ private static final int DEFAULT_TIMEOUT = 1000;
+ // Keep the same as ServiceStateProvider#SERVICE_STATE which is NOT same as
+ // Telephony.ServiceStateTable.AUTHORITY;
+ private static final String SERVICE_STATE = "service_state";
+
+ private ContentResolver mContentResolver;
+ private TelephonyManager mTelephonyManager;
+ private int mSubId;
+ private @Nullable ServiceState mInitialServiceState;
+
+ @Before
+ public void setUp() {
+ assumeTrue(hasTelephonyFeature());
+
+ mContentResolver = getInstrumentation().getContext().getContentResolver();
+ mTelephonyManager =
+ getInstrumentation().getContext().getSystemService(TelephonyManager.class);
+ mSubId = SubscriptionManager.getDefaultSubscriptionId();
+ mInitialServiceState = mTelephonyManager.getServiceState();
+ }
+
+ @After
+ public void tearDown() {
+ if (!hasTelephonyFeature()) {
+ return;
+ }
+
+ // Recover the initial ServiceState to remove the impact of manual ServiceState insertion.
+ if (mInitialServiceState != null) {
+ insertServiceState(mInitialServiceState);
+ }
+ }
+
+ /**
+ * Verifies that the ServiceStateTable CONTENT_URI and AUTHORITY is valid.
+ */
+ @Test
+ public void testUriAndAuthority() {
+ Uri uri = Telephony.ServiceStateTable.CONTENT_URI;
+ assertThat(uri).isEqualTo(Uri.parse("content://service-state/"));
+
+ String authority = Telephony.ServiceStateTable.AUTHORITY;
+ assertThat(authority).isEqualTo("service-state");
+ }
+
+ /**
+ * Verifies that the voice reg state is valid and matches ServiceState#getState().
+ */
+ @Test
+ public void testGetVoiceRegState_query() {
+ try (Cursor cursor = mContentResolver.query(Telephony.ServiceStateTable.CONTENT_URI,
+ new String[]{VOICE_REG_STATE}, null, null)) {
+ assertThat(cursor.getCount()).isEqualTo(1);
+ cursor.moveToNext();
+
+ int voiceRegState = cursor.getInt(cursor.getColumnIndex(VOICE_REG_STATE));
+ assertThat(voiceRegState).isEqualTo(mTelephonyManager.getServiceState().getState());
+ }
+ }
+
+ /**
+ * Verifies that when voice reg state did not change, the observer should not receive the
+ * notification.
+ */
+ @Test
+ public void testGetVoiceRegState_noChangeObserved() throws Exception {
+ ServiceState oldSS = new ServiceState();
+ oldSS.setStateOutOfService();
+ oldSS.setState(ServiceState.STATE_OUT_OF_SERVICE);
+
+ ServiceState copyOfOldSS = new ServiceState();
+ copyOfOldSS.setStateOutOfService();
+ copyOfOldSS.setState(ServiceState.STATE_OUT_OF_SERVICE);
+ // set additional fields which is not related to voice reg state
+ copyOfOldSS.setChannelNumber(65536);
+ copyOfOldSS.setIsManualSelection(true);
+
+ verifyNotificationObservedWhenFieldChanged(
+ VOICE_REG_STATE, oldSS, copyOfOldSS, false /*expectChange*/);
+ }
+
+ /**
+ * Verifies that when voice reg state changed, the observer should receive the notification.
+ */
+ @Test
+ public void testGetVoiceRegState_changeObserved() throws Exception {
+ ServiceState oldSS = new ServiceState();
+ oldSS.setStateOutOfService();
+ oldSS.setState(ServiceState.STATE_OUT_OF_SERVICE);
+
+ ServiceState newSS = new ServiceState();
+ newSS.setStateOutOfService();
+ newSS.setState(ServiceState.STATE_POWER_OFF);
+
+ verifyNotificationObservedWhenFieldChanged(
+ VOICE_REG_STATE, oldSS, newSS, true /*expectChange*/);
+ }
+
+ /**
+ * Verifies that the data network type is valid and matches ServiceState#getDataNetworkType()
+ */
+ @Test
+ public void testGetDataNetworkType_query() {
+ try (Cursor cursor = mContentResolver.query(Telephony.ServiceStateTable.CONTENT_URI,
+ new String[]{DATA_NETWORK_TYPE}, null, null)) {
+ assertThat(cursor.getCount()).isEqualTo(1);
+ cursor.moveToNext();
+
+ int dataNetworkType = cursor.getInt(cursor.getColumnIndex(DATA_NETWORK_TYPE));
+ assertThat(dataNetworkType).isEqualTo(
+ mTelephonyManager.getServiceState().getDataNetworkType());
+ }
+ }
+
+ /**
+ * Verifies that when data network type did not change, the observer should not receive the
+ * notification.
+ */
+ @Test
+ public void testDataNetworkType_noChangeObserved() throws Exception {
+ ServiceState oldSS = new ServiceState();
+ oldSS.setStateOutOfService();
+
+ ServiceState copyOfOldSS = new ServiceState();
+ copyOfOldSS.setStateOutOfService();
+
+ // Add a DOMAIN_CS NRI which should not update DataNetworkType
+ NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+ .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+ .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_GPRS)
+ .setRegistrationState(REGISTRATION_STATE_HOME)
+ .build();
+ copyOfOldSS.addNetworkRegistrationInfo(nri);
+
+ verifyNotificationObservedWhenFieldChanged(
+ DATA_NETWORK_TYPE, oldSS, copyOfOldSS, false /*expectChange*/);
+ }
+
+ /**
+ * Verifies that when data network type changed, the observer should receive the notification.
+ */
+ @Test
+ public void testDataNetworkType_changeObserved() throws Exception {
+ // While we don't have a method to directly set dataNetworkType, we emulate a ServiceState
+ // change that will trigger the change of dataNetworkType, according to the logic in
+ // ServiceState#getDataNetworkType()
+ ServiceState oldSS = new ServiceState();
+ oldSS.setStateOutOfService();
+
+ ServiceState newSS = new ServiceState();
+ newSS.setStateOutOfService();
+
+ NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+ .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+ .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
+ .setRegistrationState(REGISTRATION_STATE_HOME)
+ .build();
+ newSS.addNetworkRegistrationInfo(nri);
+
+ verifyNotificationObservedWhenFieldChanged(
+ DATA_NETWORK_TYPE, oldSS, newSS, true /*expectChange*/);
+ }
+
+ /**
+ * Verifies that the duplex mode is valid and matches ServiceState#getDuplexMode().
+ */
+ @Test
+ public void testGetDuplexMode_query() {
+ try (Cursor cursor = mContentResolver.query(Telephony.ServiceStateTable.CONTENT_URI,
+ new String[]{DUPLEX_MODE}, null, null)) {
+ assertThat(cursor.getCount()).isEqualTo(1);
+ cursor.moveToNext();
+
+ int duplexMode = cursor.getInt(cursor.getColumnIndex(DUPLEX_MODE));
+ assertThat(duplexMode).isEqualTo(mTelephonyManager.getServiceState().getDuplexMode());
+ }
+ }
+
+ /**
+ * Verifies that even we have duplex mode change, the observer should not receive the
+ * notification (duplex mode is a poll-only field).
+ */
+ @Test
+ public void testGetDuplexMode_noChangeObserved() throws Exception {
+ ServiceState oldSS = new ServiceState();
+ oldSS.setStateOutOfService();
+
+ ServiceState newSS = new ServiceState();
+ newSS.setStateOutOfService();
+
+ // Add NRI to trigger SS with duplex mode updated
+ NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+ .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+ .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
+ .build();
+ newSS.addNetworkRegistrationInfo(nri);
+ newSS.setChannelNumber(65536); // EutranBand.BAND_65, DUPLEX_MODE_FDD
+
+ verifyNotificationObservedWhenFieldChanged(
+ DUPLEX_MODE, oldSS, newSS, false /*expectChange*/);
+ }
+
+ /**
+ * Verifies that the data reg state is valid and matches ServiceState#getDataRegState()
+ */
+ @Test
+ public void testGetDataRegState_query() {
+ try (Cursor cursor = mContentResolver.query(Telephony.ServiceStateTable.CONTENT_URI,
+ new String[]{DATA_REG_STATE}, null, null)) {
+ assertThat(cursor.getCount()).isEqualTo(1);
+ cursor.moveToNext();
+
+ int dataRegState = cursor.getInt(cursor.getColumnIndex(DATA_REG_STATE));
+ assertThat(dataRegState).isEqualTo(
+ mTelephonyManager.getServiceState().getDataRegState());
+ }
+ }
+
+ /**
+ * Verifies that when data reg state did not change, the observer should not receive the
+ * notification.
+ */
+ @Test
+ public void testGetDataRegState_noChangeObserved() throws Exception {
+ ServiceState oldSS = new ServiceState();
+ oldSS.setStateOutOfService();
+ oldSS.setState(ServiceState.STATE_OUT_OF_SERVICE);
+
+ ServiceState copyOfOldSS = new ServiceState();
+ copyOfOldSS.setStateOutOfService();
+ copyOfOldSS.setState(ServiceState.STATE_OUT_OF_SERVICE);
+ // set additional fields which is not related to data reg state
+ copyOfOldSS.setChannelNumber(65536);
+ copyOfOldSS.setIsManualSelection(true);
+
+ verifyNotificationObservedWhenFieldChanged(
+ DATA_REG_STATE, oldSS, copyOfOldSS, false /*expectChange*/);
+ }
+
+ /**
+ * Verifies that when data reg state changed, the observer should receive the notification.
+ */
+ @Test
+ public void testGetDataRegState_changeObserved() throws Exception {
+ ServiceState oldSS = new ServiceState();
+ oldSS.setStateOutOfService();
+
+ ServiceState newSS = new ServiceState();
+ newSS.setStateOutOfService();
+ newSS.setStateOff();
+
+ verifyNotificationObservedWhenFieldChanged(
+ DATA_REG_STATE, oldSS, newSS, true /*expectChange*/);
+ }
+
+ /**
+ * Insert new ServiceState over the old ServiceState and expect the observer receiving the
+ * notification over the observed field change.
+ */
+ private void verifyNotificationObservedWhenFieldChanged(String field, ServiceState oldSS,
+ ServiceState newSS, boolean expectChange) throws Exception {
+ final Uri uriForSubAndField =
+ Telephony.ServiceStateTable.getUriForSubscriptionIdAndField(mSubId, field);
+ insertServiceState(oldSS);
+
+ RecordingContentObserver observer = new RecordingContentObserver();
+ mContentResolver.registerContentObserver(uriForSubAndField, false, observer);
+ assertWithMessage("Observer is NOT empty in the beginning.").that(
+ observer.mObserved).isEmpty();
+
+ insertServiceState(newSS);
+
+ if (expectChange) {
+ // Only verify we did receive the notification for the expected field, instead of the
+ // number of notifications we received to remove flakiness for different cases.
+ PollingCheck.check(
+ "Expect notification when " + field + " updated.",
+ DEFAULT_TIMEOUT, () -> observer.mObserved.contains(uriForSubAndField));
+ } else {
+ // Let the bullets fly for a while before we check the target.
+ try {
+ Thread.sleep(DEFAULT_TIMEOUT);
+ } catch (InterruptedException ignored) {
+ }
+
+ // Fields in ServiceState are not orthogonal. In case we do receive notification(s),
+ // further check if it is for the expected field.
+ assertWithMessage("Unexpected notification for " + field).that(
+ observer.mObserved).doesNotContain(uriForSubAndField);
+
+ }
+
+ mContentResolver.unregisterContentObserver(observer);
+ }
+
+ // Manually insert the ServiceState into table to test the notification.
+ private void insertServiceState(ServiceState state) {
+ ContentValues values = getContentValuesForServiceState(state);
+ SystemUtil.runWithShellPermissionIdentity(
+ () -> mContentResolver.insert(
+ Telephony.ServiceStateTable.getUriForSubscriptionId(mSubId), values),
+ Manifest.permission.MODIFY_PHONE_STATE);
+ }
+
+ // Copied from ServiceStateProvider#getContentValuesForServiceState
+ private static ContentValues getContentValuesForServiceState(ServiceState state) {
+ ContentValues values = new ContentValues();
+ final Parcel p = Parcel.obtain();
+ state.writeToParcel(p, 0);
+ values.put(SERVICE_STATE, p.marshall());
+ return values;
+ }
+
+ private static class RecordingContentObserver extends ContentObserver {
+ List<Uri> mObserved = new CopyOnWriteArrayList<>();
+
+ RecordingContentObserver() {
+ super(new Handler(Looper.getMainLooper()));
+ }
+
+ @Override
+ public void onChange(boolean selfChange, @Nullable Uri uri) {
+ mObserved.add(uri);
+ }
+ }
+
+ private static boolean hasTelephonyFeature() {
+ return getInstrumentation().getContext().getPackageManager().hasSystemFeature(
+ FEATURE_TELEPHONY);
+ }
+}
diff --git a/tests/tests/text/res/values/style.xml b/tests/tests/text/res/values/style.xml
index 905a3b9..3bfaba9 100644
--- a/tests/tests/text/res/values/style.xml
+++ b/tests/tests/text/res/values/style.xml
@@ -82,7 +82,8 @@
</style>
<style name="TextAppearanceWithBoldAndWeight">
- <item name="android:textStyle">bold</item>
+ <item name="android:typeface">sans</item>
+ <item name="android:textStyle">bold</item>
<item name="android:textFontWeight">500</item>
</style>
diff --git a/tests/tests/toast/OWNERS b/tests/tests/toast/OWNERS
index 9363c1a..47186b7 100644
--- a/tests/tests/toast/OWNERS
+++ b/tests/tests/toast/OWNERS
@@ -1,3 +1,4 @@
# Bug component: 137825
svetoslavganov@google.com
toddke@google.com
+patb@google.com
diff --git a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
index 9135e56..d784389 100755
--- a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
+++ b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
@@ -107,14 +107,14 @@
// Access APIs guarded by a platform defined signature permissions
try {
+ assertSame(packageManager.checkPermission(Manifest.permission.ANSWER_PHONE_CALLS,
+ context.getPackageName()), PackageManager.PERMISSION_DENIED);
getInstrumentation().getUiAutomation().adoptShellPermissionIdentity();
// Access APIs guarded by a platform defined signature permission
activityManager.getPackageImportance("foo.bar.baz");
// Grant ourselves a runtime permission (was granted at install)
- assertSame(packageManager.checkPermission(Manifest.permission.ANSWER_PHONE_CALLS,
- context.getPackageName()), PackageManager.PERMISSION_DENIED);
packageManager.grantRuntimePermission(context.getPackageName(),
Manifest.permission.ANSWER_PHONE_CALLS, Process.myUserHandle());
} catch (SecurityException e) {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java
index 5b8cb48..05fc15f 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java
@@ -47,7 +47,6 @@
import java.util.concurrent.CountDownLatch;
@LargeTest
-@SkipPresubmit // TODO: Figure out what's going on with this b/134716377
@RunWith(AndroidJUnit4.class)
public class SurfaceViewTests extends ActivityTestBase {
diff --git a/tests/tests/util/Android.bp b/tests/tests/util/Android.bp
index 0c5de3a..3998282 100644
--- a/tests/tests/util/Android.bp
+++ b/tests/tests/util/Android.bp
@@ -34,4 +34,5 @@
],
srcs: ["src/**/*.java"],
platform_apis: true,
+ min_sdk_version: "30",
}
diff --git a/tests/tests/util/AndroidManifest.xml b/tests/tests/util/AndroidManifest.xml
index 77ab380..10de8ef 100644
--- a/tests/tests/util/AndroidManifest.xml
+++ b/tests/tests/util/AndroidManifest.xml
@@ -26,6 +26,8 @@
<uses-library android:name="android.test.runner" />
</application>
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
+
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="android.util.cts"
android:label="CTS tests of android.util">
diff --git a/tests/tests/util/src/android/util/cts/TimeUtilsTest.java b/tests/tests/util/src/android/util/cts/TimeUtilsTest.java
index d20ccdb..e08704d 100644
--- a/tests/tests/util/src/android/util/cts/TimeUtilsTest.java
+++ b/tests/tests/util/src/android/util/cts/TimeUtilsTest.java
@@ -16,6 +16,9 @@
package android.util.cts;
import static android.util.TimeUtils.isTimeBetween;
+
+import static com.google.common.truth.Truth.assertThat;
+
import static junit.framework.TestCase.assertFalse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@@ -27,6 +30,8 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.google.common.truth.Truth;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -172,6 +177,15 @@
}
@Test
+ public void getTimeZoneIdsForCountryCode_doesNotShowNoLongerActiveNames() {
+ List<String> usTimeZones = TimeUtils.getTimeZoneIdsForCountryCode("us");
+
+ assertThat(usTimeZones).contains("America/New_York");
+ // America/Detroit was available only till 27 April 1975
+ assertThat(usTimeZones).doesNotContain("America/Detroit");
+ }
+
+ @Test
public void testGetTimeZoneIdsForCountryCode_unknownCountryCode() {
String unknownCountryCode = "zx81";
assertNull(TimeUtils.getTimeZoneIdsForCountryCode(unknownCountryCode));
diff --git a/tests/tests/vcn/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java b/tests/tests/vcn/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java
new file mode 100644
index 0000000..20bdc0a
--- /dev/null
+++ b/tests/tests/vcn/src/android/net/vcn/cts/VcnGatewayConnectionConfigTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.net.vcn.cts;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.net.ipsec.ike.IkeSessionParams;
+import android.net.ipsec.ike.IkeTunnelConnectionParams;
+import android.net.vcn.VcnGatewayConnectionConfig;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class VcnGatewayConnectionConfigTest extends VcnTestBase {
+ private static final String VCN_GATEWAY_CONNECTION_NAME = "test-vcn-gateway-connection";
+ private static final long[] RETRY_INTERNAL_MILLIS =
+ new long[] {
+ TimeUnit.SECONDS.toMillis(1),
+ TimeUnit.MINUTES.toMillis(1),
+ TimeUnit.HOURS.toMillis(1)
+ };
+ private static final int MAX_MTU = 1360;
+
+ private static VcnGatewayConnectionConfig.Builder buildVcnGatewayConnectionConfigBase() {
+ return new VcnGatewayConnectionConfig.Builder(
+ VCN_GATEWAY_CONNECTION_NAME, buildTunnelConnectionParams())
+ .addExposedCapability(NET_CAPABILITY_INTERNET)
+ .setRetryIntervalsMillis(RETRY_INTERNAL_MILLIS)
+ .setMaxMtu(MAX_MTU);
+ }
+
+ public static VcnGatewayConnectionConfig buildVcnGatewayConnectionConfig() {
+ return buildVcnGatewayConnectionConfigBase().build();
+ }
+
+ @Test
+ public void testBuildVcnGatewayConnectionConfig() throws Exception {
+ final VcnGatewayConnectionConfig gatewayConnConfig = buildVcnGatewayConnectionConfig();
+
+ assertEquals(VCN_GATEWAY_CONNECTION_NAME, gatewayConnConfig.getGatewayConnectionName());
+ assertEquals(buildTunnelConnectionParams(), gatewayConnConfig.getTunnelConnectionParams());
+ assertArrayEquals(
+ new int[] {NET_CAPABILITY_INTERNET}, gatewayConnConfig.getExposedCapabilities());
+ assertArrayEquals(RETRY_INTERNAL_MILLIS, gatewayConnConfig.getRetryIntervalsMillis());
+ }
+
+ @Test
+ public void testBuilderAddRemove() throws Exception {
+ final VcnGatewayConnectionConfig gatewayConnConfig =
+ buildVcnGatewayConnectionConfigBase()
+ .addExposedCapability(NET_CAPABILITY_DUN)
+ .removeExposedCapability(NET_CAPABILITY_DUN)
+ .build();
+
+ assertArrayEquals(
+ new int[] {NET_CAPABILITY_INTERNET}, gatewayConnConfig.getExposedCapabilities());
+ }
+
+ @Test
+ public void testBuildWithoutMobikeEnabled() {
+ final IkeSessionParams ikeParams =
+ getIkeSessionParamsBase().removeIkeOption(IKE_OPTION_MOBIKE).build();
+ final IkeTunnelConnectionParams tunnelParams = buildTunnelConnectionParams(ikeParams);
+
+ try {
+ new VcnGatewayConnectionConfig.Builder(VCN_GATEWAY_CONNECTION_NAME, tunnelParams);
+ fail("Expected exception if MOBIKE not configured");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+}
diff --git a/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java b/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java
index a5646fa..e406815 100644
--- a/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java
+++ b/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java
@@ -17,14 +17,11 @@
package android.net.vcn.cts;
import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP;
-import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
-import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assume.assumeTrue;
import android.annotation.NonNull;
@@ -33,15 +30,7 @@
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.NetworkCapabilities;
-import android.net.ipsec.ike.ChildSaProposal;
-import android.net.ipsec.ike.IkeFqdnIdentification;
-import android.net.ipsec.ike.IkeSaProposal;
-import android.net.ipsec.ike.IkeSessionParams;
-import android.net.ipsec.ike.SaProposal;
-import android.net.ipsec.ike.TunnelModeChildSessionParams;
import android.net.vcn.VcnConfig;
-import android.net.vcn.VcnControlPlaneIkeConfig;
-import android.net.vcn.VcnGatewayConnectionConfig;
import android.net.vcn.VcnManager;
import android.os.ParcelUuid;
import android.telephony.SubscriptionManager;
@@ -62,7 +51,7 @@
import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
-public class VcnManagerTest {
+public class VcnManagerTest extends VcnTestBase {
private static final String TAG = VcnManagerTest.class.getSimpleName();
private static final int TIMEOUT_MS = 500;
@@ -89,79 +78,29 @@
}
private VcnConfig buildVcnConfig() {
- final IkeSaProposal ikeProposal =
- new IkeSaProposal.Builder()
- .addEncryptionAlgorithm(
- ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128)
- .addDhGroup(DH_GROUP_2048_BIT_MODP)
- .addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_XCBC)
- .build();
-
- final String serverHostname = "2001:db8:1::100";
- final String testLocalId = "test.client.com";
- final String testRemoteId = "test.server.com";
- final byte[] psk = "psk".getBytes();
-
- // TODO: b/180521384: Build the IkeSessionParams without a Context when the no-arg
- // IkeSessionParams.Builder constructor is exposed.
- final IkeSessionParams ikeParams =
- new IkeSessionParams.Builder(mContext)
- .setServerHostname(serverHostname)
- .addSaProposal(ikeProposal)
- .setLocalIdentification(new IkeFqdnIdentification(testLocalId))
- .setRemoteIdentification(new IkeFqdnIdentification(testRemoteId))
- .setAuthPsk(psk)
- .build();
-
- final ChildSaProposal childProposal =
- new ChildSaProposal.Builder()
- .addEncryptionAlgorithm(
- ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128)
- .build();
- final TunnelModeChildSessionParams childParams =
- new TunnelModeChildSessionParams.Builder().addSaProposal(childProposal).build();
-
- final VcnControlPlaneIkeConfig controlConfig =
- new VcnControlPlaneIkeConfig(ikeParams, childParams);
-
- final VcnGatewayConnectionConfig gatewayConnConfig =
- new VcnGatewayConnectionConfig.Builder(controlConfig)
- .addExposedCapability(NET_CAPABILITY_INTERNET)
- .addRequiredUnderlyingCapability(NET_CAPABILITY_INTERNET)
- .setRetryInterval(
- new long[] {
- TimeUnit.SECONDS.toMillis(1),
- TimeUnit.MINUTES.toMillis(1),
- TimeUnit.HOURS.toMillis(1)
- })
- .setMaxMtu(1360)
- .build();
-
return new VcnConfig.Builder(mContext)
- .addGatewayConnectionConfig(gatewayConnConfig)
+ .addGatewayConnectionConfig(
+ VcnGatewayConnectionConfigTest.buildVcnGatewayConnectionConfig())
.build();
}
+ private int verifyAndGetValidDataSubId() {
+ final int dataSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+ assertNotEquals(
+ "There must be an active data subscription to complete CTS",
+ INVALID_SUBSCRIPTION_ID,
+ dataSubId);
+ return dataSubId;
+ }
+
@Test(expected = SecurityException.class)
public void testSetVcnConfig_noCarrierPrivileges() throws Exception {
- // TODO: b/180521384: Remove the assertion when constructing IkeSessionParams does not
- // require an active default network.
- assertNotNull(
- "You must have an active network connection to complete CTS",
- mConnectivityManager.getActiveNetwork());
-
mVcnManager.setVcnConfig(new ParcelUuid(UUID.randomUUID()), buildVcnConfig());
}
@Test
public void testSetVcnConfig_withCarrierPrivileges() throws Exception {
- // TODO: b/180521384: Remove the assertion when constructing IkeSessionParams does not
- // require an active default network.
- assertNotNull(
- "You must have an active network connection to complete CTS",
- mConnectivityManager.getActiveNetwork());
-
- final int dataSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+ final int dataSubId = verifyAndGetValidDataSubId();
CarrierPrivilegeUtils.withCarrierPrivileges(mContext, dataSubId, () -> {
SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, dataSubId, (subGrp) -> {
mVcnManager.setVcnConfig(subGrp, buildVcnConfig());
@@ -178,7 +117,8 @@
@Test
public void testClearVcnConfig_withCarrierPrivileges() throws Exception {
- final int dataSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+ final int dataSubId = verifyAndGetValidDataSubId();
+
CarrierPrivilegeUtils.withCarrierPrivileges(mContext, dataSubId, () -> {
SubscriptionGroupUtils.withEphemeralSubscriptionGroup(mContext, dataSubId, (subGrp) -> {
mVcnManager.clearVcnConfig(subGrp);
@@ -186,9 +126,9 @@
});
}
- /** Test implementation of VcnNetworkPolicyListener for verification purposes. */
- private static class TestVcnNetworkPolicyListener
- implements VcnManager.VcnNetworkPolicyListener {
+ /** Test implementation of VcnNetworkPolicyChangeListener for verification purposes. */
+ private static class TestVcnNetworkPolicyChangeListener
+ implements VcnManager.VcnNetworkPolicyChangeListener {
private final CompletableFuture<Void> mFutureOnPolicyChanged = new CompletableFuture<>();
@Override
@@ -202,21 +142,24 @@
}
@Test(expected = SecurityException.class)
- public void testAddVcnNetworkPolicyListener_noNetworkFactoryPermission() throws Exception {
- final TestVcnNetworkPolicyListener listener = new TestVcnNetworkPolicyListener();
+ public void testAddVcnNetworkPolicyChangeListener_noNetworkFactoryPermission()
+ throws Exception {
+ final TestVcnNetworkPolicyChangeListener listener =
+ new TestVcnNetworkPolicyChangeListener();
try {
- mVcnManager.addVcnNetworkPolicyListener(INLINE_EXECUTOR, listener);
+ mVcnManager.addVcnNetworkPolicyChangeListener(INLINE_EXECUTOR, listener);
} finally {
- mVcnManager.removeVcnNetworkPolicyListener(listener);
+ mVcnManager.removeVcnNetworkPolicyChangeListener(listener);
}
}
@Test
- public void testRemoveVcnNetworkPolicyListener() {
- final TestVcnNetworkPolicyListener listener = new TestVcnNetworkPolicyListener();
+ public void testRemoveVcnNetworkPolicyChangeListener_noNetworkFactoryPermission() {
+ final TestVcnNetworkPolicyChangeListener listener =
+ new TestVcnNetworkPolicyChangeListener();
- mVcnManager.removeVcnNetworkPolicyListener(listener);
+ mVcnManager.removeVcnNetworkPolicyChangeListener(listener);
}
@Test(expected = SecurityException.class)
@@ -229,25 +172,25 @@
/** Test implementation of VcnStatusCallback for verification purposes. */
private static class TestVcnStatusCallback extends VcnManager.VcnStatusCallback {
- private final CompletableFuture<Integer> mFutureOnVcnStatusChanged =
+ private final CompletableFuture<Integer> mFutureOnStatusChanged =
new CompletableFuture<>();
private final CompletableFuture<GatewayConnectionError> mFutureOnGatewayConnectionError =
new CompletableFuture<>();
@Override
- public void onVcnStatusChanged(int statusCode) {
- mFutureOnVcnStatusChanged.complete(statusCode);
+ public void onStatusChanged(int statusCode) {
+ mFutureOnStatusChanged.complete(statusCode);
}
@Override
public void onGatewayConnectionError(
- @NonNull int[] networkCapabilities, int errorCode, @Nullable Throwable detail) {
+ @NonNull String gatewayConnectionName, int errorCode, @Nullable Throwable detail) {
mFutureOnGatewayConnectionError.complete(
- new GatewayConnectionError(networkCapabilities, errorCode, detail));
+ new GatewayConnectionError(gatewayConnectionName, errorCode, detail));
}
- public int awaitOnVcnStatusChanged() throws Exception {
- return mFutureOnVcnStatusChanged.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ public int awaitOnStatusChanged() throws Exception {
+ return mFutureOnStatusChanged.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
public GatewayConnectionError awaitOnGatewayConnectionError() throws Exception {
@@ -257,13 +200,13 @@
/** Info class for organizing VcnStatusCallback#onGatewayConnectionError response data. */
private static class GatewayConnectionError {
- @NonNull public final int[] networkCapabilities;
+ @NonNull public final String gatewayConnectionName;
public final int errorCode;
@Nullable public final Throwable detail;
public GatewayConnectionError(
- @NonNull int[] networkCapabilities, int errorCode, @Nullable Throwable detail) {
- this.networkCapabilities = networkCapabilities.clone();
+ @NonNull String gatewayConnectionName, int errorCode, @Nullable Throwable detail) {
+ this.gatewayConnectionName = gatewayConnectionName;
this.errorCode = errorCode;
this.detail = detail;
}
@@ -281,12 +224,12 @@
@Test
public void testRegisterVcnStatusCallback() throws Exception {
final TestVcnStatusCallback callback = new TestVcnStatusCallback();
- final int subId = SubscriptionManager.getDefaultSubscriptionId();
+ final int subId = verifyAndGetValidDataSubId();
try {
registerVcnStatusCallbackForSubId(callback, subId);
- final int statusCode = callback.awaitOnVcnStatusChanged();
+ final int statusCode = callback.awaitOnStatusChanged();
assertEquals(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED, statusCode);
} finally {
mVcnManager.unregisterVcnStatusCallback(callback);
@@ -296,7 +239,7 @@
@Test
public void testRegisterVcnStatusCallback_reuseUnregisteredCallback() throws Exception {
final TestVcnStatusCallback callback = new TestVcnStatusCallback();
- final int subId = SubscriptionManager.getDefaultSubscriptionId();
+ final int subId = verifyAndGetValidDataSubId();
try {
registerVcnStatusCallbackForSubId(callback, subId);
@@ -310,7 +253,7 @@
@Test(expected = IllegalStateException.class)
public void testRegisterVcnStatusCallback_duplicateRegister() throws Exception {
final TestVcnStatusCallback callback = new TestVcnStatusCallback();
- final int subId = SubscriptionManager.getDefaultSubscriptionId();
+ final int subId = verifyAndGetValidDataSubId();
try {
registerVcnStatusCallbackForSubId(callback, subId);
diff --git a/tests/tests/vcn/src/android/net/vcn/cts/VcnTestBase.java b/tests/tests/vcn/src/android/net/vcn/cts/VcnTestBase.java
new file mode 100644
index 0000000..7ed201e
--- /dev/null
+++ b/tests/tests/vcn/src/android/net/vcn/cts/VcnTestBase.java
@@ -0,0 +1,73 @@
+/*
+ * 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.net.vcn.cts;
+
+import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
+import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
+import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC;
+
+import android.net.ipsec.ike.ChildSaProposal;
+import android.net.ipsec.ike.IkeFqdnIdentification;
+import android.net.ipsec.ike.IkeSaProposal;
+import android.net.ipsec.ike.IkeSessionParams;
+import android.net.ipsec.ike.IkeTunnelConnectionParams;
+import android.net.ipsec.ike.SaProposal;
+import android.net.ipsec.ike.TunnelModeChildSessionParams;
+
+public class VcnTestBase {
+ protected static IkeTunnelConnectionParams buildTunnelConnectionParams() {
+ final IkeSessionParams ikeParams = getIkeSessionParamsBase().build();
+ return buildTunnelConnectionParams(ikeParams);
+ }
+
+ protected static IkeTunnelConnectionParams buildTunnelConnectionParams(
+ IkeSessionParams ikeParams) {
+ final ChildSaProposal childProposal =
+ new ChildSaProposal.Builder()
+ .addEncryptionAlgorithm(
+ ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128)
+ .build();
+ final TunnelModeChildSessionParams childParams =
+ new TunnelModeChildSessionParams.Builder().addSaProposal(childProposal).build();
+
+ return new IkeTunnelConnectionParams(ikeParams, childParams);
+ }
+
+ protected static IkeSessionParams.Builder getIkeSessionParamsBase() {
+ final IkeSaProposal ikeProposal =
+ new IkeSaProposal.Builder()
+ .addEncryptionAlgorithm(
+ ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128)
+ .addDhGroup(DH_GROUP_2048_BIT_MODP)
+ .addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_XCBC)
+ .build();
+
+ final String serverHostname = "2001:db8:1::100";
+ final String testLocalId = "test.client.com";
+ final String testRemoteId = "test.server.com";
+ final byte[] psk = "psk".getBytes();
+
+ return new IkeSessionParams.Builder()
+ .setServerHostname(serverHostname)
+ .addSaProposal(ikeProposal)
+ .setLocalIdentification(new IkeFqdnIdentification(testLocalId))
+ .setRemoteIdentification(new IkeFqdnIdentification(testRemoteId))
+ .setAuthPsk(psk)
+ .addIkeOption(IKE_OPTION_MOBIKE);
+ }
+}
diff --git a/tests/tests/view/Android.bp b/tests/tests/view/Android.bp
new file mode 100644
index 0000000..22a9411
--- /dev/null
+++ b/tests/tests/view/Android.bp
@@ -0,0 +1,60 @@
+// 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.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+ name: "CtsViewTestCases",
+ defaults: ["cts_defaults"],
+
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+
+ compile_multilib: "both",
+
+ libs: [
+ "android.test.runner.stubs",
+ "android.test.base.stubs",
+ ],
+
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "compatibility-device-util-axt",
+ "ctsdeviceutillegacy-axt",
+ "ctstestrunner-axt",
+ "mockito-target-minus-junit4",
+ "platform-test-annotations",
+ "ub-uiautomator",
+ "truth-prebuilt",
+ "CtsSurfaceValidatorLib",
+ "cts-wm-util",
+ ],
+
+ jni_libs: [
+ "libctsview_jni",
+ "libnativehelper_compat_libc++",
+ ],
+
+ srcs: [
+ "src/**/*.java",
+ ],
+
+ sdk_version: "test_current",
+}
diff --git a/tests/tests/view/Android.mk b/tests/tests/view/Android.mk
deleted file mode 100644
index 3c16650..0000000
--- a/tests/tests/view/Android.mk
+++ /dev/null
@@ -1,54 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-
-LOCAL_MULTILIB := both
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- androidx.test.rules \
- androidx.test.ext.junit \
- compatibility-device-util-axt \
- ctsdeviceutillegacy-axt \
- ctstestrunner-axt \
- mockito-target-minus-junit4 \
- platform-test-annotations \
- ub-uiautomator \
- truth-prebuilt \
- CtsSurfaceValidatorLib \
- cts-wm-util
-
-
-LOCAL_JNI_SHARED_LIBRARIES := libctsview_jni libnativehelper_compat_libc++
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsViewTestCases
-LOCAL_SDK_VERSION := test_current
-
-include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/view/jni/OWNERS b/tests/tests/view/jni/OWNERS
new file mode 100644
index 0000000..0fd2da2
--- /dev/null
+++ b/tests/tests/view/jni/OWNERS
@@ -0,0 +1 @@
+per-file android_view_cts_ASurfaceControlTest.cpp = file:platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS
diff --git a/tests/tests/view/res/layout-round/gesture_exclusion_basic.xml b/tests/tests/view/res/layout-round/gesture_exclusion_basic.xml
new file mode 100644
index 0000000..71754b6
--- /dev/null
+++ b/tests/tests/view/res/layout-round/gesture_exclusion_basic.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/abslistview_root"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+ <View android:id="@+id/animating_view"
+ android:layout_width="5px"
+ android:layout_height="5px"
+ android:layout_gravity="center|left"
+ android:background="#ff00ff00" />
+</FrameLayout>
diff --git a/tests/tests/view/src/android/view/cts/KeyEventInterceptTest.java b/tests/tests/view/src/android/view/cts/KeyEventInterceptTest.java
index abae9e7..bf73550 100644
--- a/tests/tests/view/src/android/view/cts/KeyEventInterceptTest.java
+++ b/tests/tests/view/src/android/view/cts/KeyEventInterceptTest.java
@@ -29,7 +29,7 @@
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
-import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.WindowUtil;
import org.junit.Before;
import org.junit.Rule;
@@ -67,7 +67,7 @@
public void setup() {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mActivity = mActivityRule.getActivity();
- PollingCheck.waitFor(mActivity::hasWindowFocus);
+ WindowUtil.waitForFocus(mActivity);
}
@Test
diff --git a/tests/tests/view/src/android/view/cts/OWNERS b/tests/tests/view/src/android/view/cts/OWNERS
new file mode 100644
index 0000000..3da545b
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/OWNERS
@@ -0,0 +1,2 @@
+per-file ASurfaceControlTest.java = file:platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS
+per-file SurfaceViewSyncTest.java = file:platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS
diff --git a/tests/tests/view/src/android/view/cts/VerifyInputEventTest.java b/tests/tests/view/src/android/view/cts/VerifyInputEventTest.java
index 9262dfc..68d7353 100644
--- a/tests/tests/view/src/android/view/cts/VerifyInputEventTest.java
+++ b/tests/tests/view/src/android/view/cts/VerifyInputEventTest.java
@@ -47,7 +47,7 @@
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
-import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.WindowUtil;
import org.junit.Before;
import org.junit.Rule;
@@ -80,7 +80,7 @@
assertNotNull(mInputManager);
mAutomation = instrumentation.getUiAutomation();
mActivity = mActivityRule.getActivity();
- PollingCheck.waitFor(mActivity::hasWindowFocus);
+ WindowUtil.waitForFocus(mActivity);
}
@Test
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index 3f9f563..25a8a26 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -115,6 +115,7 @@
import com.android.compatibility.common.util.CtsMouseUtil;
import com.android.compatibility.common.util.CtsTouchUtils;
import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.WindowUtil;
import org.junit.Before;
import org.junit.Rule;
@@ -164,7 +165,7 @@
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mContext = mInstrumentation.getTargetContext();
mActivity = mActivityRule.getActivity();
- PollingCheck.waitFor(mActivity::hasWindowFocus);
+ WindowUtil.waitForFocus(mActivity);
mResources = mActivity.getResources();
mMockParent = new MockViewParent(mActivity);
PollingCheck.waitFor(5 * DateUtils.SECOND_IN_MILLIS, mActivity::hasWindowFocus);
diff --git a/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java b/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java
index aa752a5..edfb8c4 100644
--- a/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java
@@ -42,8 +42,8 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.CtsTouchUtils;
-import com.android.compatibility.common.util.PollingCheck;
import com.android.compatibility.common.util.WidgetTestUtils;
+import com.android.compatibility.common.util.WindowUtil;
import org.junit.Before;
import org.junit.Rule;
@@ -70,7 +70,7 @@
public void setup() throws Throwable {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mActivity = mActivityRule.getActivity();
- PollingCheck.waitFor(mActivity::hasWindowFocus);
+ WindowUtil.waitForFocus(mActivity);
layout(R.layout.viewtreeobserver_layout);
mLinearLayout = (LinearLayout) mActivity.findViewById(R.id.linearlayout);
diff --git a/tests/tests/view/src/android/view/cts/ViewUnbufferedTest.java b/tests/tests/view/src/android/view/cts/ViewUnbufferedTest.java
index b0ec086..94acb96 100644
--- a/tests/tests/view/src/android/view/cts/ViewUnbufferedTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewUnbufferedTest.java
@@ -40,6 +40,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.WindowUtil;
import org.junit.After;
import org.junit.Before;
@@ -127,7 +128,7 @@
mSentEvents.clear();
mReceivedCountPerFrame.set(0);
mMaxReceivedCountPerFrame = 0;
- PollingCheck.waitFor(mActivity::hasWindowFocus);
+ WindowUtil.waitForFocus(mActivity);
mView = mActivity.findViewById(R.id.test_view);
}
diff --git a/tests/tests/view/surfacevalidator/Android.bp b/tests/tests/view/surfacevalidator/Android.bp
new file mode 100644
index 0000000..bad8631
--- /dev/null
+++ b/tests/tests/view/surfacevalidator/Android.bp
@@ -0,0 +1,33 @@
+// 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_test_helper_library {
+
+ name: "CtsSurfaceValidatorLib",
+
+ sdk_version: "test_current",
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "androidx.test.rules",
+ "cts-wm-util",
+ "ub-uiautomator",
+ ],
+
+}
diff --git a/tests/tests/view/surfacevalidator/Android.mk b/tests/tests/view/surfacevalidator/Android.mk
deleted file mode 100644
index 54129cd..0000000
--- a/tests/tests/view/surfacevalidator/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2019 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := CtsSurfaceValidatorLib
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SDK_VERSION := test_current
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- androidx.test.rules \
- cts-wm-util \
- ub-uiautomator
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/tests/view/surfacevalidator/OWNERS b/tests/tests/view/surfacevalidator/OWNERS
new file mode 100644
index 0000000..361760d
--- /dev/null
+++ b/tests/tests/view/surfacevalidator/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS
diff --git a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java
index 9401370..6e643f8 100644
--- a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java
+++ b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java
@@ -151,7 +151,6 @@
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
startActivityForResult(mProjectionManager.createScreenCaptureIntent(), PERMISSION_CODE);
- dismissPermissionDialog();
mProjectionServiceBound = true;
}
diff --git a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/PixelColor.java b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/PixelColor.java
index b50944b..bd37fa0 100644
--- a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/PixelColor.java
+++ b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/PixelColor.java
@@ -59,27 +59,10 @@
}
private int getMinValue(short color) {
- if (color - 4 > 0) {
- return color - 4;
- }
- return 0;
+ return Math.max(color - 4, 0);
}
private int getMaxValue(short color) {
- if (color + 4 < 0xFF) {
- return color + 4;
- }
- return 0xFF;
- }
-
- public void addToPixelCounter(ScriptC_PixelCounter script) {
- script.set_MIN_ALPHA(mMinAlpha);
- script.set_MAX_ALPHA(mMaxAlpha);
- script.set_MIN_RED(mMinRed);
- script.set_MAX_RED(mMaxRed);
- script.set_MIN_BLUE(mMinBlue);
- script.set_MAX_BLUE(mMaxBlue);
- script.set_MIN_GREEN(mMinGreen);
- script.set_MAX_GREEN(mMaxGreen);
+ return Math.min(color + 4, 0xFF);
}
}
diff --git a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/PixelCounter.rscript b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/PixelCounter.rscript
deleted file mode 100644
index b4fe3be..0000000
--- a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/PixelCounter.rscript
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma version(1)
-#pragma rs java_package_name(android.view.cts.surfacevalidator)
-#pragma rs reduce(countBlackishPixels) accumulator(countBlackishPixelsAccum) combiner(countBlackishPixelsCombiner)
-
-uchar MIN_ALPHA;
-uchar MAX_ALPHA;
-uchar MIN_RED;
-uchar MAX_RED;
-uchar MIN_GREEN;
-uchar MAX_GREEN;
-uchar MIN_BLUE;
-uchar MAX_BLUE;
-int BOUNDS[4];
-
-static void countBlackishPixelsAccum(int *accum, uchar4 pixel, uint32_t x, uint32_t y) {
-
- if (pixel.a <= MAX_ALPHA
- && pixel.a >= MIN_ALPHA
- && pixel.r <= MAX_RED
- && pixel.r >= MIN_RED
- && pixel.g <= MAX_GREEN
- && pixel.g >= MIN_GREEN
- && pixel.b <= MAX_BLUE
- && pixel.b >= MIN_BLUE
- && x >= BOUNDS[0]
- && x < BOUNDS[2]
- && y >= BOUNDS[1]
- && y < BOUNDS[3]) {
- *accum += 1;
- }
-}
-
-static void countBlackishPixelsCombiner(int *accum, const int *other){
- *accum += *other;
-}
diff --git a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java
deleted file mode 100644
index f1a1660..0000000
--- a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.view.cts.surfacevalidator;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Trace;
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-import android.renderscript.Type;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.Surface;
-
-public class SurfacePixelValidator {
- private static final String TAG = "SurfacePixelValidator";
-
- /**
- * Observed that first few frames have errors with SurfaceView placement, so we skip for now.
- * b/29603849 tracking that issue.
- */
- private static final int NUM_FIRST_FRAMES_SKIPPED = 8;
-
- private static final int MAX_CAPTURED_FAILURES = 5;
-
- private final int mWidth;
- private final int mHeight;
-
- private final HandlerThread mWorkerThread;
- private final Handler mWorkerHandler;
-
- private final PixelChecker mPixelChecker;
-
- private final RenderScript mRS;
-
- private final Allocation mInPixelsAllocation;
- private final ScriptC_PixelCounter mScript;
-
-
- private final Object mResultLock = new Object();
- private int mResultSuccessFrames;
- private int mResultFailureFrames;
- private SparseArray<Bitmap> mFirstFailures = new SparseArray<>(MAX_CAPTURED_FAILURES);
-
- private Runnable mConsumeRunnable = new Runnable() {
- int mNumSkipped = 0;
- @Override
- public void run() {
- Trace.beginSection("consume buffer");
- mInPixelsAllocation.ioReceive();
- Trace.endSection();
-
- Trace.beginSection("compare and sum");
- int blackishPixelCount = mScript.reduce_countBlackishPixels(mInPixelsAllocation).get();
- Trace.endSection();
-
- boolean success = mPixelChecker.checkPixels(blackishPixelCount, mWidth, mHeight);
- synchronized (mResultLock) {
- if (mNumSkipped < NUM_FIRST_FRAMES_SKIPPED) {
- mNumSkipped++;
- Log.d(TAG, "skipped frame nr " + mNumSkipped + ", success = " + success);
- } else {
- if (success) {
- mResultSuccessFrames++;
- } else {
- mResultFailureFrames++;
- int totalFramesSeen = mResultSuccessFrames + mResultFailureFrames;
- Log.d(TAG, "Failure (pixel count = " + blackishPixelCount
- + ") occurred on frame " + totalFramesSeen);
-
- if (mFirstFailures.size() < MAX_CAPTURED_FAILURES) {
- Log.d(TAG, "Capturing bitmap #" + mFirstFailures.size());
- // error, worth looking at...
- Bitmap capture = Bitmap.createBitmap(mWidth, mHeight,
- Bitmap.Config.ARGB_8888);
- mInPixelsAllocation.copyTo(capture);
- mFirstFailures.put(totalFramesSeen, capture);
- }
- }
- }
- }
- }
- };
-
- public SurfacePixelValidator(Context context, Point size, Rect boundsToCheck,
- PixelChecker pixelChecker) {
- mWidth = size.x;
- mHeight = size.y;
-
- mWorkerThread = new HandlerThread("SurfacePixelValidator");
- mWorkerThread.start();
- mWorkerHandler = new Handler(mWorkerThread.getLooper());
-
- mPixelChecker = pixelChecker;
-
- mRS = RenderScript.create(context);
- mScript = new ScriptC_PixelCounter(mRS);
-
- mInPixelsAllocation = createBufferQueueAllocation();
- mScript.set_BOUNDS(new int[] {boundsToCheck.left, boundsToCheck.top,
- boundsToCheck.right, boundsToCheck.bottom});
- pixelChecker.getColor().addToPixelCounter(mScript);
-
- mInPixelsAllocation.setOnBufferAvailableListener(
- allocation -> mWorkerHandler.post(mConsumeRunnable));
- }
-
- public Surface getSurface() {
- return mInPixelsAllocation.getSurface();
- }
-
- private Allocation createBufferQueueAllocation() {
- return Allocation.createAllocations(mRS, Type.createXY(mRS,
- Element.RGBA_8888(mRS)
- /*Element.U32(mRS)*/, mWidth, mHeight),
- Allocation.USAGE_SCRIPT | Allocation.USAGE_IO_INPUT,
- 1)[0];
- }
-
- /**
- * Shuts down processing pipeline, and returns current pass/fail counts.
- *
- * Wait for pipeline to flush before calling this method. If not, frames that are still in
- * flight may be lost.
- */
- public void finish(CapturedActivity.TestResult testResult) {
- synchronized (mResultLock) {
- // could in theory miss results still processing, but only if latency is extremely high.
- // Caller should only call this
- testResult.failFrames = mResultFailureFrames;
- testResult.passFrames = mResultSuccessFrames;
-
- for (int i = 0; i < mFirstFailures.size(); i++) {
- testResult.failures.put(mFirstFailures.keyAt(i), mFirstFailures.valueAt(i));
- }
- }
- mWorkerThread.quitSafely();
- }
-}
diff --git a/tests/tests/webkit/assets/webkit/page_with_link.html b/tests/tests/webkit/assets/webkit/page_with_link.html
index 50fb78a..4fbe869 100644
--- a/tests/tests/webkit/assets/webkit/page_with_link.html
+++ b/tests/tests/webkit/assets/webkit/page_with_link.html
@@ -15,6 +15,8 @@
<html>
<body>
- <a href="http://foo.com" id="link">a link</a>
+ <!-- This is a relative link to an arbitrary page also hosted on this
+ server. -->
+ <a href="/assets/webkit/test_blankPage.html" id="link">a link</a>
</body>
</html>
diff --git a/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java b/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java
index ac0283c..360895a 100644
--- a/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java
+++ b/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java
@@ -57,7 +57,11 @@
public static final String LOGIN_FORM_URL = "webkit/test_loginForm.html";
- public static final String EXT_WEB_URL1 = "http://www.example.com/";
+ // Note: tests should avoid loading external URLs if at all possible, since any changes to that
+ // public site (even if it doesn't currently exist) can affect test behavior. The ".test" TLD is
+ // OK because (1) it's reserved for testing by RFC2606 and (2) the test never navigates to this
+ // page.
+ public static final String EXT_WEB_URL1 = "http://www.example.test/";
public static final String PARAM_ASSET_URL = "webkit/test_queryparam.html";
public static final String ANCHOR_ASSET_URL = "webkit/test_anchor.html";
@@ -66,8 +70,9 @@
public static final String DATABASE_ACCESS_URL = "webkit/test_databaseaccess.html";
public static final String STOP_LOADING_URL = "webkit/test_stop_loading.html";
public static final String BLANK_TAG_URL = "webkit/blank_tag.html";
+ // A page with a link to an arbitrary page controlled by the test server (in this case,
+ // BLANK_PAGE_URL).
public static final String PAGE_WITH_LINK_URL = "webkit/page_with_link.html";
- public static final String URL_IN_PAGE_WITH_LINK = "http://foo.com/";
// Not a real page, just triggers a 404 response.
public static final String NON_EXISTENT_PAGE_URL = "webkit/generate_404.html";
public static final String BAD_IMAGE_PAGE_URL = "webkit/test_bad_image_url.html";
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index 81ea695..a99e9af 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -204,8 +204,10 @@
}
}.run();
assertEquals(mainCallCount, mainWebViewClient.getShouldOverrideUrlLoadingCallCount());
- assertEquals(
- TestHtmlConstants.URL_IN_PAGE_WITH_LINK, childWebViewClient.getLastShouldOverrideUrl());
+ // PAGE_WITH_LINK_URL has a link to BLANK_PAGE_URL (an arbitrary page also controlled by the
+ // test server)
+ assertEquals(mWebServer.getAssetUrl(TestHtmlConstants.BLANK_PAGE_URL),
+ childWebViewClient.getLastShouldOverrideUrl());
}
private void clickOnLinkUsingJs(final String linkId, WebViewOnUiThread webViewOnUiThread) {
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewRenderProcessClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewRenderProcessClientTest.java
index 2d6a196..39e3eb9 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewRenderProcessClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewRenderProcessClientTest.java
@@ -23,7 +23,7 @@
import android.webkit.WebView;
import android.webkit.WebViewRenderProcess;
import android.webkit.WebViewRenderProcessClient;
-
+import com.android.compatibility.common.util.NullWebViewUtils;
import com.google.common.util.concurrent.SettableFuture;
import java.util.concurrent.CountDownLatch;
@@ -44,7 +44,9 @@
super.setUp();
final WebViewCtsActivity activity = getActivity();
WebView webView = activity.getWebView();
- mOnUiThread = new WebViewOnUiThread(webView);
+ if (webView != null) {
+ mOnUiThread = new WebViewOnUiThread(webView);
+ }
}
@Override
@@ -145,10 +147,17 @@
}
public void testWebViewRenderProcessClientWithoutExecutor() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
testWebViewRenderProcessClientOnExecutor(null);
}
public void testWebViewRenderProcessClientWithExecutor() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+
final AtomicInteger executorCount = new AtomicInteger();
testWebViewRenderProcessClientOnExecutor(new Executor() {
@Override
@@ -161,6 +170,10 @@
}
public void testSetWebViewRenderProcessClient() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+
assertNull("Initially the renderer client should be null",
mOnUiThread.getWebViewRenderProcessClient());
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewRenderProcessTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewRenderProcessTest.java
index 6e25b5f..941d970 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewRenderProcessTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewRenderProcessTest.java
@@ -25,6 +25,7 @@
import android.webkit.WebViewClient;
import android.webkit.WebViewRenderProcess;
+import com.android.compatibility.common.util.NullWebViewUtils;
import com.google.common.util.concurrent.SettableFuture;
import java.util.concurrent.Future;
@@ -42,7 +43,9 @@
super.setUp();
final WebViewCtsActivity activity = getActivity();
WebView webView = activity.getWebView();
- mOnUiThread = new WebViewOnUiThread(webView);
+ if (webView != null) {
+ mOnUiThread = new WebViewOnUiThread(webView);
+ }
}
@Override
@@ -104,6 +107,10 @@
}
public void testGetWebViewRenderProcess() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+
final WebView webView = mOnUiThread.getWebView();
final WebViewRenderProcess preStartRenderProcess = getRenderProcessOnUiThread(webView);
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewSslTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewSslTest.java
index d59d395..bb7994e 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewSslTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewSslTest.java
@@ -822,6 +822,26 @@
assertEquals(callCount + 1, webViewClient.getClientCertRequestCount());
}
+ /**
+ * Loads a url until a specific error code. This is meant to be used when two different errors
+ * can race. Specifically, this is meant to be used to workaround the TLS 1.3 (Android Q and
+ * above) race condition where a server <b>may</b> close the connection at the same time the
+ * client sends the HTTP request, emitting {@code ERROR_CONNECT} instead of {@code
+ * ERROR_FAILED_SSL_HANDSHAKE}.
+ */
+ private void loadUrlUntilError(SslErrorWebViewClient client, String url,
+ int expectedErrorCode) {
+ int maxTries = 40;
+ for (int i = 0; i < maxTries; i++) {
+ mOnUiThread.loadUrlAndWaitForCompletion(url);
+ if (client.onReceivedErrorCode() == expectedErrorCode) {
+ return;
+ }
+ }
+ throw new RuntimeException(
+ "Reached max number of tries and never saw error " + expectedErrorCode);
+ }
+
public void testIgnoreClientCertRequest() throws Throwable {
if (!NullWebViewUtils.isWebViewAvailable()) {
return;
@@ -833,18 +853,23 @@
clearClientCertPreferences();
// Ignore the request. Load should fail.
webViewClient.setAction(ClientCertWebViewClient.IGNORE);
- mOnUiThread.loadUrlAndWaitForCompletion(url);
+ loadUrlUntilError(webViewClient, url, WebViewClient.ERROR_FAILED_SSL_HANDSHAKE);
assertFalse(TestHtmlConstants.HELLO_WORLD_TITLE.equals(mOnUiThread.getTitle()));
- assertFailedHandshakeOrConnectionError(webViewClient.onReceivedErrorCode());
+ // At least one of the loads done by loadUrlUntilError() should produce
+ // onReceivedClientCertRequest.
+ assertTrue("onReceivedClientCertRequest should be called at least once",
+ webViewClient.getClientCertRequestCount() >= 1);
// Load a different page from the same domain, ignoring the request. We should get a callback,
// and load should fail.
int callCount = webViewClient.getClientCertRequestCount();
url = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1);
- mOnUiThread.loadUrlAndWaitForCompletion(url);
+ loadUrlUntilError(webViewClient, url, WebViewClient.ERROR_FAILED_SSL_HANDSHAKE);
assertFalse(TestHtmlConstants.HTML_URL1_TITLE.equals(mOnUiThread.getTitle()));
- assertFailedHandshakeOrConnectionError(webViewClient.onReceivedErrorCode());
- assertEquals(callCount + 1, webViewClient.getClientCertRequestCount());
+ // At least one of the loads done by loadUrlUntilError() should produce
+ // onReceivedClientCertRequest.
+ assertTrue("onReceivedClientCertRequest should be called at least once for second URL",
+ webViewClient.getClientCertRequestCount() >= callCount + 1);
// Reload, proceeding the request. Load should succeed.
webViewClient.setAction(ClientCertWebViewClient.PROCEED);
diff --git a/tests/tests/widget/AndroidTest.xml b/tests/tests/widget/AndroidTest.xml
index b9311c6..ab96e6f 100644
--- a/tests/tests/widget/AndroidTest.xml
+++ b/tests/tests/widget/AndroidTest.xml
@@ -19,15 +19,35 @@
<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="force-install-mode" value="FULL"/>
+ <option name="test-file-name" value="TestIme.apk" />
+ <option name="test-file-name" value="CtsWidgetApp.apk" />
+ </target_preparer>
+
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsWidgetTestCases.apk" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="force-install-mode" value="FULL"/>
- <option name="test-file-name" value="CtsWidgetApp.apk" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <!--
+ Workaround for the possible downtime between [adb install <IME.apk>]
+ and [adb shell ime <IME ID>]. See b/188105339 for detais.
+ -->
+ <option name="run-command" value="am wait-for-broadcast-idle" />
+ <!--
+ One more workaround. Consider increasing this if the test is still unstable.
+ See b/188105339 for detais.
+ -->
+ <option name="run-command" value="sleep 1" />
+ <option name="run-command" value="ime enable com.android.cts.testime/.TestIme" />
+ <option name="run-command" value="ime set com.android.cts.testime/.TestIme" />
+ <option name="teardown-command" value="ime reset" />
</target_preparer>
+
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.widget.cts" />
<option name="runtime-hint" value="11m55s" />
diff --git a/tests/tests/widget/res/layout-round/edittext_layout.xml b/tests/tests/widget/res/layout-round/edittext_layout.xml
new file mode 100644
index 0000000..4f7f62b
--- /dev/null
+++ b/tests/tests/widget/res/layout-round/edittext_layout.xml
@@ -0,0 +1,60 @@
+<?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.
+-->
+
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <LinearLayout
+ android:id="@+id/edit_text"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <EditText
+ android:id="@+id/edittext_simple1"
+ android:layout_width="200dp"
+ android:layout_marginLeft="50dip"
+ android:layout_height="wrap_content" />
+
+ <EditText
+ android:id="@+id/edittext_simple2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <EditText android:id="@+id/edittext1"
+ style="@android:style/Widget.EditText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dip"
+ android:scrollHorizontally="true"
+ android:capitalize="sentences"
+ android:autoText="false"
+ android:maxLines="3"
+ android:textColor="#FF0000"
+ android:text="@string/edit_text" />
+
+ <EditText
+ android:id="@+id/edittext_autosize"
+ android:layout_width="300dp"
+ android:layout_height="400dp"
+ android:text="@string/long_text"
+ android:autoSizeTextType="uniform"
+ android:textSize="50dp"
+ android:autoSizeStepGranularity="2dp" />
+ </LinearLayout>
+</ScrollView>
diff --git a/tests/tests/widget/res/layout-watch/magnifier_activity_centered_view_layout.xml b/tests/tests/widget/res/layout-watch/magnifier_activity_centered_view_layout.xml
new file mode 100644
index 0000000..4a3b211
--- /dev/null
+++ b/tests/tests/widget/res/layout-watch/magnifier_activity_centered_view_layout.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/magnifier_activity_centered_view_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center" >
+ <FrameLayout
+ android:id="@+id/magnifier_centered_view"
+ android:layout_width="40dp"
+ android:layout_height="16dp"
+ android:background="@android:color/holo_blue_bright" />
+</LinearLayout>
diff --git a/tests/tests/widget/res/layout-watch/magnifier_activity_scrollable_views_layout.xml b/tests/tests/widget/res/layout-watch/magnifier_activity_scrollable_views_layout.xml
new file mode 100644
index 0000000..450d3a0
--- /dev/null
+++ b/tests/tests/widget/res/layout-watch/magnifier_activity_scrollable_views_layout.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/magnifier_activity_scrollable_views_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal"
+ android:orientation="vertical" >
+
+ <HorizontalScrollView
+ android:id="@+id/horizontal_scroll_container"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content">
+ <FrameLayout
+ android:id="@+id/magnifier_activity_horizontally_scrolled_view"
+ android:layout_width="wrap_content"
+ android:layout_height="40dp"
+ android:minWidth="500dp"
+ android:background="@android:color/holo_blue_bright" />
+ </HorizontalScrollView>
+
+ <ScrollView
+ android:id="@+id/vertical_scroll_container"
+ android:layout_width="wrap_content"
+ android:layout_height="40dp" >
+ <FrameLayout
+ android:id="@+id/magnifier_activity_vertically_scrolled_view"
+ android:layout_width="40dp"
+ android:layout_height="wrap_content"
+ android:minHeight="500dp"
+ android:background="@android:color/holo_red_light" />
+ </ScrollView>
+</LinearLayout>
diff --git a/tests/tests/widget/res/layout/magnifier_activity_centered_view_layout.xml b/tests/tests/widget/res/layout/magnifier_activity_centered_view_layout.xml
index 1a11740..1bad59c 100644
--- a/tests/tests/widget/res/layout/magnifier_activity_centered_view_layout.xml
+++ b/tests/tests/widget/res/layout/magnifier_activity_centered_view_layout.xml
@@ -23,7 +23,7 @@
android:gravity="center" >
<FrameLayout
android:id="@+id/magnifier_centered_view"
- android:layout_width="100dp"
+ android:layout_width="80dp"
android:layout_height="56dp"
android:background="@android:color/holo_blue_bright" />
</LinearLayout>
diff --git a/tests/tests/widget/res/layout/magnifier_activity_scrollable_views_layout.xml b/tests/tests/widget/res/layout/magnifier_activity_scrollable_views_layout.xml
index 4b2bc6f..f1ccef1 100644
--- a/tests/tests/widget/res/layout/magnifier_activity_scrollable_views_layout.xml
+++ b/tests/tests/widget/res/layout/magnifier_activity_scrollable_views_layout.xml
@@ -38,8 +38,7 @@
<ScrollView
android:id="@+id/vertical_scroll_container"
android:layout_width="wrap_content"
- android:layout_height="100dp"
- android:layout_marginTop="100dp" >
+ android:layout_height="100dp" >
<FrameLayout
android:id="@+id/magnifier_activity_vertically_scrolled_view"
android:layout_width="100dp"
diff --git a/tests/tests/widget/res/layout/timepicker.xml b/tests/tests/widget/res/layout/timepicker.xml
index 8581008..d23366a 100644
--- a/tests/tests/widget/res/layout/timepicker.xml
+++ b/tests/tests/widget/res/layout/timepicker.xml
@@ -20,6 +20,7 @@
android:orientation="vertical">
<TimePicker
android:id="@+id/timepicker_clock"
+ android:timePickerMode="clock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TimePicker
diff --git a/tests/tests/widget/src/android/widget/cts/EditTextTest.java b/tests/tests/widget/src/android/widget/cts/EditTextTest.java
index 957edf0..c5e40ca 100755
--- a/tests/tests/widget/src/android/widget/cts/EditTextTest.java
+++ b/tests/tests/widget/src/android/widget/cts/EditTextTest.java
@@ -467,7 +467,7 @@
@Test
public void testCursorDrag() throws Exception {
AtomicReference<SparseArray<Point>> dragStartEnd = new AtomicReference<>();
- String text = "Hello world, how are you doing today?";
+ String text = "Hello, how are you today?";
mInstrumentation.runOnMainSync(() -> {
mEditText1.setText(text);
mEditText1.requestFocus();
@@ -497,8 +497,10 @@
}
private static Point getScreenCoords(TextView textView, int offset) {
- // Get the x,y coordinates for the given offset in the text. These are relative to the view.
- int x = (int) textView.getLayout().getPrimaryHorizontal(offset);
+ // Get the x,y coordinates for the given offset in the text.
+ // These are relative to the view.
+ // Please note that we compensate for rounding error here by adding 1.
+ int x = (int) textView.getLayout().getPrimaryHorizontal(offset) + 1;
int line = textView.getLayout().getLineForOffset(offset);
int yTop = textView.getLayout().getLineTop(line);
int yBottom = textView.getLayout().getLineBottom(line);
diff --git a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
index 148e6a8..8d9e2a2 100644
--- a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
@@ -498,7 +498,7 @@
final Rect rect = new Rect();
mPopupWindow.getBackground().getPadding(rect);
CtsTouchUtils.emulateTapOnView(instrumentation, mActivityRule, popupListView,
- -rect.left - 20, popupListView.getHeight() + rect.top + rect.bottom + 20);
+ -rect.left - 20, popupListView.getHeight() / 2);
// At this point our popup should not be showing and should have notified its
// dismiss listener
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index e0fb5e8..adf7e67 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -4201,6 +4201,9 @@
@Test
public void testHandleDrawable_canBeSet_whenInsertionHandleIsShown() throws Throwable {
+ if (isWatch()) {
+ return; // watch does not support overlay keyboard.
+ }
initTextViewForTypingOnUiThread();
mActivityRule.runOnUiThread(() -> {
mTextView.setTextIsSelectable(true);
@@ -6572,18 +6575,7 @@
public void testSetGetBreakStrategy() {
TextView tv = new TextView(mActivity);
- final PackageManager pm = mInstrumentation.getTargetContext().getPackageManager();
-
- // The default value is from the theme, here the default is BREAK_STRATEGY_HIGH_QUALITY for
- // TextView except for Android Wear. The default value for Android Wear is
- // BREAK_STRATEGY_BALANCED.
- if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
- // Android Wear
- assertEquals(Layout.BREAK_STRATEGY_BALANCED, tv.getBreakStrategy());
- } else {
- // All other form factor.
- assertEquals(Layout.BREAK_STRATEGY_HIGH_QUALITY, tv.getBreakStrategy());
- }
+ assertEquals(Layout.BREAK_STRATEGY_HIGH_QUALITY, tv.getBreakStrategy());
tv.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE);
assertEquals(Layout.BREAK_STRATEGY_SIMPLE, tv.getBreakStrategy());
diff --git a/tests/tests/widget/src/android/widget/cts/ToastTest.java b/tests/tests/widget/src/android/widget/cts/ToastTest.java
index fb1c7ba..d3718a0 100644
--- a/tests/tests/widget/src/android/widget/cts/ToastTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToastTest.java
@@ -16,6 +16,7 @@
package android.widget.cts;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static com.google.common.truth.Truth.assertThat;
@@ -28,6 +29,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;
+import android.app.ActivityOptions;
import android.app.UiAutomation;
import android.app.UiAutomation.AccessibilityEventFilter;
import android.content.BroadcastReceiver;
@@ -449,7 +451,7 @@
* watch. Unlike the phone, which displays toast centered horizontally at the bottom of the
* screen, the watch now displays toast in the center of the screen.
*/
- if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ if (Gravity.CENTER == mToast.getGravity()) {
assertTrue(xy1[0] > xy2[0]);
assertTrue(xy1[1] > xy2[1]);
} else {
@@ -522,6 +524,7 @@
@UiThreadTest
@Test
public void testMakeTextFromString() {
+ assumeFalse("Skipping test: Watch does not support new Toast behavior yet", isWatch());
Toast toast = Toast.makeText(mContext, "android", Toast.LENGTH_SHORT);
assertNotNull(toast);
assertEquals(Toast.LENGTH_SHORT, toast.getDuration());
@@ -550,6 +553,7 @@
@UiThreadTest
@Test
public void testMakeTextFromResource() {
+ assumeFalse("Skipping test: Watch does not support new Toast behavior yet", isWatch());
Toast toast = Toast.makeText(mContext, R.string.hello_world, Toast.LENGTH_LONG);
assertNotNull(toast);
@@ -604,6 +608,7 @@
@UiThreadTest
@Test(expected = IllegalStateException.class)
public void testSetTextFromStringNonNullView() {
+ assumeFalse("Skipping test: Watch does not support new Toast behavior yet", isWatch());
Toast toast = Toast.makeText(mContext, R.string.text, Toast.LENGTH_LONG);
toast.setView(new TextView(mContext));
toast.setText(null);
@@ -699,6 +704,7 @@
@Test
public void testTextToastAllowed_whenInTheBackground() throws Throwable {
+ assumeFalse("Skipping test: Watch does not support new Toast behavior yet", isWatch());
// Make it background
mActivityRule.finishActivity();
makeToast();
@@ -729,25 +735,25 @@
Intent intent = new Intent();
intent.setComponent(COMPONENT_TRANSLUCENT_ACTIVITY);
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(intent);
+ // Launch the translucent activity in fullscreen to ensure the test activity won't resume
+ // even on the freeform-first multi-window device.
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ mContext.startActivity(intent, options.toBundle());
activityStarted.block();
makeCustomToast();
View view = mToast.getView();
mActivityRule.runOnUiThread(mToast::show);
- // The custom toast should not be blocked in multi-window mode. Otherwise, it should be.
- if (mActivityRule.getActivity().isInMultiWindowMode()) {
- assertShowCustomToast(view);
- } else {
- assertNotShowCustomToast(view);
- }
+ assertNotShowCustomToast(view);
mContext.sendBroadcast(new Intent(ACTION_TRANSLUCENT_ACTIVITY_FINISH));
}
@UiThreadTest
@Test
public void testGetWindowParams_whenTextToast_returnsNull() {
+ assumeFalse("Skipping test: Watch does not support new Toast behavior yet", isWatch());
Toast toast = Toast.makeText(mContext, "Text", Toast.LENGTH_LONG);
assertNull(toast.getWindowParams());
}
@@ -843,6 +849,11 @@
return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
}
+ private boolean isWatch() {
+ PackageManager pm = mContext.getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
+ }
+
private static void uncheck(ThrowingRunnable runnable) {
try {
runnable.run();
diff --git a/tests/tests/widget29/src/android/widget/cts29/ToastTest.java b/tests/tests/widget29/src/android/widget/cts29/ToastTest.java
index 49cd0de..cb917b7 100644
--- a/tests/tests/widget29/src/android/widget/cts29/ToastTest.java
+++ b/tests/tests/widget29/src/android/widget/cts29/ToastTest.java
@@ -341,7 +341,7 @@
* watch. Unlike the phone, which displays toast centered horizontally at the bottom of the
* screen, the watch now displays toast in the center of the screen.
*/
- if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ if (Gravity.CENTER == mToast.getGravity()) {
assertTrue(xy1[0] > xy2[0]);
assertTrue(xy1[1] > xy2[1]);
} else {
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/EasyConnectStatusCallbackTest.java b/tests/tests/wifi/src/android/net/wifi/cts/EasyConnectStatusCallbackTest.java
index 07256a3..e0768d9 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/EasyConnectStatusCallbackTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/EasyConnectStatusCallbackTest.java
@@ -41,7 +41,7 @@
public class EasyConnectStatusCallbackTest extends WifiJUnit3TestBase {
private static final String TEST_SSID = "\"testSsid\"";
private static final String TEST_PASSPHRASE = "\"testPassword\"";
- private static final int TEST_WAIT_DURATION_MS = 12_000; // Long delay is necessary, see below
+ private static final int TEST_WAIT_DURATION_MS = 22_000; // Long delay is necessary, see below
private WifiManager mWifiManager;
private static final String TEST_DPP_URI =
"DPP:C:81/1,117/40;I:Easy_Connect_Demo;M:000102030405;"
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java
index bdbc699a..2fb377d 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java
@@ -16,7 +16,7 @@
package android.net.wifi.cts;
-import static android.net.NetworkCapabilitiesProto.TRANSPORT_WIFI;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.os.Process.myUid;
import static com.google.common.truth.Truth.assertThat;
diff --git a/tests/tests/wrap/nowrap/Android.mk b/tests/tests/wrap/nowrap/Android.mk
index 8f50ddc..269f4ad 100644
--- a/tests/tests/wrap/nowrap/Android.mk
+++ b/tests/tests/wrap/nowrap/Android.mk
@@ -30,6 +30,8 @@
LOCAL_SDK_VERSION := current
LOCAL_PACKAGE_NAME := CtsWrapNoWrapTestCases
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_MANIFEST_FILE := AndroidManifest.xml
# Jarjar to make WrapTest unique.
diff --git a/tests/tests/wrap/wrap_debug/Android.mk b/tests/tests/wrap/wrap_debug/Android.mk
index e8d8f1f..8743cc4 100644
--- a/tests/tests/wrap/wrap_debug/Android.mk
+++ b/tests/tests/wrap/wrap_debug/Android.mk
@@ -37,6 +37,8 @@
LOCAL_PREBUILT_JNI_LIBS_x86_64 := ../wrap.sh
LOCAL_PACKAGE_NAME := CtsWrapWrapDebugTestCases
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_MANIFEST_FILE := AndroidManifest.xml
# Jarjar to make WrapTest unique.
diff --git a/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk b/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk
index 06a2850..06d1d5c 100644
--- a/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk
+++ b/tests/tests/wrap/wrap_debug_malloc_debug/Android.mk
@@ -37,6 +37,8 @@
LOCAL_PREBUILT_JNI_LIBS_x86_64 := wrap.sh
LOCAL_PACKAGE_NAME := CtsWrapWrapDebugMallocDebugTestCases
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_MANIFEST_FILE := AndroidManifest.xml
# Jarjar to make WrapTest unique.
diff --git a/tests/tests/wrap/wrap_nodebug/Android.mk b/tests/tests/wrap/wrap_nodebug/Android.mk
index aaebda2..f7823c5 100644
--- a/tests/tests/wrap/wrap_nodebug/Android.mk
+++ b/tests/tests/wrap/wrap_nodebug/Android.mk
@@ -37,6 +37,8 @@
LOCAL_PREBUILT_JNI_LIBS_x86_64 := ../wrap.sh
LOCAL_PACKAGE_NAME := CtsWrapWrapNoDebugTestCases
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
LOCAL_MANIFEST_FILE := AndroidManifest.xml
# Jarjar to make WrapTest unique.
diff --git a/tests/uwb/src/android/uwb/cts/AngleMeasurementTest.java b/tests/uwb/src/android/uwb/cts/AngleMeasurementTest.java
index c6ddead..f96b798 100644
--- a/tests/uwb/src/android/uwb/cts/AngleMeasurementTest.java
+++ b/tests/uwb/src/android/uwb/cts/AngleMeasurementTest.java
@@ -35,41 +35,52 @@
@RunWith(AndroidJUnit4.class)
public class AngleMeasurementTest {
@Test
- public void testBuilder() {
+ public void testConstructs() {
double radians = 0.1234;
double errorRadians = 0.5678;
double confidence = 0.5;
- AngleMeasurement.Builder builder = new AngleMeasurement.Builder();
- tryBuild(builder, false);
-
- builder.setRadians(radians);
- tryBuild(builder, false);
-
- builder.setErrorRadians(errorRadians);
- tryBuild(builder, false);
-
- builder.setConfidenceLevel(confidence);
- AngleMeasurement measurement = tryBuild(builder, true);
-
+ AngleMeasurement measurement = new AngleMeasurement(radians, errorRadians, confidence);
assertEquals(measurement.getRadians(), radians, 0);
assertEquals(measurement.getErrorRadians(), errorRadians, 0);
assertEquals(measurement.getConfidenceLevel(), confidence, 0);
}
- private AngleMeasurement tryBuild(AngleMeasurement.Builder builder, boolean expectSuccess) {
- AngleMeasurement measurement = null;
+ @Test
+ public void testInvalidRadians() {
+ double radians = Math.PI + 0.01;
+ double errorRadians = 0.5678;
+ double confidence = 0.5;
+
+ constructExpectFailure(radians, errorRadians, confidence);
+ constructExpectFailure(-radians, errorRadians, confidence);
+ }
+
+ @Test
+ public void testInvalidErrorRadians() {
+ double radians = 0.1234;
+ double confidence = 0.5;
+
+ constructExpectFailure(radians, -0.01, confidence);
+ constructExpectFailure(-radians, Math.PI + 0.01, confidence);
+ }
+
+ @Test
+ public void testInvalidConfidence() {
+ double radians = 0.1234;
+ double errorRadians = 0.5678;
+
+ constructExpectFailure(radians, errorRadians, -0.01);
+ constructExpectFailure(radians, errorRadians, 1.01);
+ }
+
+ private void constructExpectFailure(double radians, double errorRadians, double confidence) {
try {
- measurement = builder.build();
- if (!expectSuccess) {
- fail("Expected AngleMeasurement.Builder.build() to fail, but it succeeded");
- }
- } catch (IllegalStateException e) {
- if (expectSuccess) {
- fail("Expected AngleMeasurement.Builder.build() to succeed, but it failed");
- }
+ new AngleMeasurement(radians, errorRadians, confidence);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
}
- return measurement;
}
@Test
diff --git a/tests/uwb/src/android/uwb/cts/AngleOfArrivalMeasurementTest.java b/tests/uwb/src/android/uwb/cts/AngleOfArrivalMeasurementTest.java
index 16dc4c2..085ce2e 100644
--- a/tests/uwb/src/android/uwb/cts/AngleOfArrivalMeasurementTest.java
+++ b/tests/uwb/src/android/uwb/cts/AngleOfArrivalMeasurementTest.java
@@ -41,27 +41,15 @@
AngleMeasurement azimuth = UwbTestUtils.getAngleMeasurement();
AngleMeasurement altitude = UwbTestUtils.getAngleMeasurement();
- AngleOfArrivalMeasurement.Builder builder = new AngleOfArrivalMeasurement.Builder();
- tryBuild(builder, false);
-
+ AngleOfArrivalMeasurement.Builder builder = new AngleOfArrivalMeasurement.Builder(azimuth);
builder.setAltitude(altitude);
- tryBuild(builder, false);
- builder.setAzimuth(azimuth);
AngleOfArrivalMeasurement measurement = tryBuild(builder, true);
assertEquals(azimuth, measurement.getAzimuth());
assertEquals(altitude, measurement.getAltitude());
}
- private AngleMeasurement getAngleMeasurement(double radian, double error, double confidence) {
- return new AngleMeasurement.Builder()
- .setRadians(radian)
- .setErrorRadians(error)
- .setConfidenceLevel(confidence)
- .build();
- }
-
private AngleOfArrivalMeasurement tryBuild(AngleOfArrivalMeasurement.Builder builder,
boolean expectSuccess) {
AngleOfArrivalMeasurement measurement = null;
diff --git a/tests/uwb/src/android/uwb/cts/RangingSessionTest.java b/tests/uwb/src/android/uwb/cts/RangingSessionTest.java
index b936142..b9725f1 100644
--- a/tests/uwb/src/android/uwb/cts/RangingSessionTest.java
+++ b/tests/uwb/src/android/uwb/cts/RangingSessionTest.java
@@ -172,11 +172,11 @@
session.start(PARAMS);
verifyNoThrowIllegalState(session::stop);
- verify(callback, times(1)).onStopped();
+ verify(callback, times(1)).onStopped(anyInt(), any());
// Calling stop again should throw an illegal state
verifyThrowIllegalState(session::stop);
- verify(callback, times(1)).onStopped();
+ verify(callback, times(1)).onStopped(anyInt(), any());
}
@Test
@@ -202,7 +202,7 @@
verify(callback, times(2)).onReconfigured(any());
verifyOpenState(session, true);
- session.onRangingStopped();
+ session.onRangingStopped(REASON, PARAMS);
verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS));
verify(callback, times(3)).onReconfigured(any());
verifyOpenState(session, true);
@@ -363,7 +363,7 @@
@Override
public Object answer(InvocationOnMock invocation) {
- mSession.onRangingStopped();
+ mSession.onRangingStopped(REASON, PARAMS);
return null;
}
}
diff --git a/tests/uwb/src/android/uwb/cts/UwbTestUtils.java b/tests/uwb/src/android/uwb/cts/UwbTestUtils.java
index b5d8e1b..3790b52 100644
--- a/tests/uwb/src/android/uwb/cts/UwbTestUtils.java
+++ b/tests/uwb/src/android/uwb/cts/UwbTestUtils.java
@@ -39,17 +39,15 @@
}
public static AngleMeasurement getAngleMeasurement() {
- return new AngleMeasurement.Builder()
- .setRadians(getDoubleInRange(-Math.PI, Math.PI))
- .setErrorRadians(getDoubleInRange(0, Math.PI))
- .setConfidenceLevel(getDoubleInRange(0, 1))
- .build();
+ return new AngleMeasurement(
+ getDoubleInRange(-Math.PI, Math.PI),
+ getDoubleInRange(0, Math.PI),
+ getDoubleInRange(0, 1));
}
public static AngleOfArrivalMeasurement getAngleOfArrivalMeasurement() {
- return new AngleOfArrivalMeasurement.Builder()
+ return new AngleOfArrivalMeasurement.Builder(getAngleMeasurement())
.setAltitude(getAngleMeasurement())
- .setAzimuth(getAngleMeasurement())
.build();
}
diff --git a/tests/video/Android.bp b/tests/video/Android.bp
index e3f5133b..55eaa74 100644
--- a/tests/video/Android.bp
+++ b/tests/video/Android.bp
@@ -29,6 +29,8 @@
"android.test.runner",
"android.test.base",
],
+ platform_apis: true,
+ jni_uses_sdk_apis: true,
jni_libs: [
"libctscodecutils_jni",
"libnativehelper_compat_libc++",
@@ -39,5 +41,5 @@
"cts",
"general-tests",
],
- sdk_version: "test_current",
+ min_sdk_version: "29",
}
diff --git a/tests/video/AndroidManifest.xml b/tests/video/AndroidManifest.xml
index 534fc3d..3b25dd5 100644
--- a/tests/video/AndroidManifest.xml
+++ b/tests/video/AndroidManifest.xml
@@ -18,10 +18,14 @@
package="android.video.cts">
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application>
+ android:requestLegacyExternalStorage="true"
+ android:usesCleartextTraffic="true">
<uses-library android:name="android.test.runner" />
+ <activity android:name="android.video.cts.CodecTestActivity" />
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="android.video.cts"
@@ -30,4 +34,5 @@
android:name="listener"
android:value="com.android.cts.runner.CtsTestRunListener" />
</instrumentation>
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
</manifest>
diff --git a/tests/video/AndroidTest.xml b/tests/video/AndroidTest.xml
index ed55f13..d99ccc1 100644
--- a/tests/video/AndroidTest.xml
+++ b/tests/video/AndroidTest.xml
@@ -19,6 +19,16 @@
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+ <option name="target" value="host" />
+ <option name="config-filename" value="CtsVideoTestCases" />
+ <option name="version" value="1.0"/>
+ </target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
+ <option name="push-all" value="true" />
+ <option name="media-folder-name" value="CtsVideoTestCases-1.1" />
+ <option name="dynamic-config-module" value="CtsVideoTestCases" />
+ </target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsVideoTestCases.apk" />
diff --git a/tests/video/DynamicConfig.xml b/tests/video/DynamicConfig.xml
new file mode 100644
index 0000000..1bf19811
--- /dev/null
+++ b/tests/video/DynamicConfig.xml
@@ -0,0 +1,5 @@
+<dynamicConfig>
+ <entry key="media_files_url">
+ <value>https://storage.googleapis.com/android_media/cts/tests/video/CtsVideoTestCases-1.1.zip</value>
+ </entry>
+</dynamicConfig>
diff --git a/tests/video/README.md b/tests/video/README.md
new file mode 100644
index 0000000..f1c9dfe
--- /dev/null
+++ b/tests/video/README.md
@@ -0,0 +1,13 @@
+## Video CTS Tests
+Current folder comprises of files necessary for:
+1. Testing video encoder/decoder performance by running encoding/decoding without displaying the raw data.
+2. Testing key operating rate for Hardware video encoder/decoder.
+
+The test vectors used by the test suite is available at [link](https://storage.googleapis.com/android_media/cts/tests/video/CtsVideoTestCases-1.1.zip) and is downloaded automatically while running tests. Manual installation of these can be done using copy_media.sh script in this directory.
+
+### Commands
+```sh
+$ atest android.video.cts
+$ atest android.video.cts.CodecEncoderPerformanceTest
+$ atest android.video.cts.CodecDecoderPerformanceTest
+```
diff --git a/tests/video/copy_media.sh b/tests/video/copy_media.sh
new file mode 100644
index 0000000..86be1e7
--- /dev/null
+++ b/tests/video/copy_media.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# 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.
+#
+
+## script to install cts video test files manually
+
+adbOptions=" "
+resLabel=CtsVideoTestCases-1.1
+srcDir="/tmp/$resLabel"
+tgtDir="/sdcard/test"
+usage="Usage: $0 [-h] [-s serial]"
+
+if [ $# -gt 0 ]; then
+ if [ "$1" = "-h" ]; then
+ echo $usage
+ exit 1
+ elif [ "$1" = "-s" -a "$2" != "" ] ; then
+ adbOptions=""$1" "$2""
+ else
+ echo "bad options"
+ echo $usage
+ exit 1
+ fi
+fi
+
+## download resources if not already done
+if [ ! -f "/tmp/$resLabel.zip" ]; then
+ wget "https://storage.googleapis.com/android_media/cts/tests/video/$resLabel.zip" -O /tmp/$resLabel.zip
+fi
+unzip -qo "/tmp/$resLabel" -d $srcDir
+
+## install on target device
+echo "adb $adbOptions push $srcDir $tgtDir"
+adb $adbOptions shell mkdir -p $tgtDir
+adb $adbOptions push $srcDir/. $tgtDir
diff --git a/tests/video/res/layout/media_decoder_surface_layout.xml b/tests/video/res/layout/media_decoder_surface_layout.xml
new file mode 100644
index 0000000..8ac820a
--- /dev/null
+++ b/tests/video/res/layout/media_decoder_surface_layout.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <SurfaceView android:id="@+id/surface"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ </SurfaceView>
+</LinearLayout>
diff --git a/tests/video/src/android/video/cts/CodecDecoderPerformanceTest.java b/tests/video/src/android/video/cts/CodecDecoderPerformanceTest.java
new file mode 100644
index 0000000..6daebf4
--- /dev/null
+++ b/tests/video/src/android/video/cts/CodecDecoderPerformanceTest.java
@@ -0,0 +1,184 @@
+/*
+ * 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.video.cts;
+
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaFormat;
+import android.util.Log;
+import android.view.Surface;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(Parameterized.class)
+public class CodecDecoderPerformanceTest extends CodecPerformanceTestBase {
+ private static final String LOG_TAG = CodecDecoderPerformanceTest.class.getSimpleName();
+ private Surface mSurface;
+
+ @Rule
+ public ActivityTestRule<CodecTestActivity> mActivityRule =
+ new ActivityTestRule<>(CodecTestActivity.class);
+
+ public CodecDecoderPerformanceTest(String decoderName, String testFile, int keyPriority,
+ float scalingFactor) {
+ super(decoderName, testFile, keyPriority, scalingFactor);
+ }
+
+ @Parameterized.Parameters(name = "{index}({0}_{2}_{3})")
+ public static Collection<Object[]> input() throws IOException {
+ final String[] fileList = new String[]{
+ // Video - Filename
+ // AVC
+ "crowd_run_720x480_30fps_avc.mp4",
+ "crowd_run_1280x720_30fps_avc.mp4",
+ "crowd_run_1920x1080_30fps_avc.mp4",
+ "crowd_run_3840x2160_30fps_avc.mp4",
+ // HEVC
+ "crowd_run_720x480_30fps_hevc.mp4",
+ "crowd_run_1280x720_30fps_hevc.mp4",
+ "crowd_run_1920x1080_30fps_hevc.mp4",
+ "crowd_run_3840x2160_30fps_hevc.mp4",
+ "crowd_run_7680x4320_30fps_hevc.mp4",
+ // VP8
+ "crowd_run_720x480_30fps_vp8.webm",
+ "crowd_run_1280x720_30fps_vp8.webm",
+ "crowd_run_1920x1080_30fps_vp8.webm",
+ "crowd_run_3840x2160_30fps_vp8.webm",
+ // VP9
+ "crowd_run_720x480_30fps_vp9.webm",
+ "crowd_run_1280x720_30fps_vp9.webm",
+ "crowd_run_1920x1080_30fps_vp9.webm",
+ "crowd_run_3840x2160_30fps_vp9.webm",
+ "crowd_run_7680x4320_30fps_vp9.webm",
+ // AV1
+ "crowd_run_720x480_30fps_av1.mp4",
+ "crowd_run_1280x720_30fps_av1.mp4",
+ "crowd_run_1920x1080_30fps_av1.mp4",
+ "crowd_run_3840x2160_30fps_av1.mp4",
+ "crowd_run_7680x4320_30fps_av1.mp4",
+ // MPEG-2
+ "crowd_run_720x480_30fps_mpeg2.mp4",
+ "crowd_run_1280x720_30fps_mpeg2.mp4",
+ "crowd_run_1920x1080_30fps_mpeg2.mp4",
+ "crowd_run_3840x2160_30fps_mpeg2.mp4",
+ "crowd_run_7680x4320_30fps_mpeg2.mp4",
+ };
+ // Prepares the params list combining with supported Hardware decoders, key priority
+ // and scaling factor.
+ final List<Object[]> argsList = new ArrayList<>();
+ for (String fileName : fileList) {
+ // Gets the format for the first video track found
+ MediaFormat format = getVideoFormat(fileName);
+ if (format == null) {
+ Log.e(LOG_TAG, "Test vector is ignored as it has no video tracks present " +
+ "in the file: " + fileName);
+ continue;
+ }
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ ArrayList<MediaFormat> formatsList = new ArrayList<>();
+ formatsList.add(format);
+ ArrayList<String> listOfDecoders = selectHardwareCodecs(mime, formatsList, null,
+ false);
+ for (String decoder : listOfDecoders) {
+ for (int keyPriority : KEY_PRIORITIES_LIST) {
+ for (float scalingFactor : SCALING_FACTORS_LIST) {
+ if (keyPriority == 1 || (scalingFactor > 0.0 && scalingFactor <= 1.0)) {
+ argsList.add(new Object[]{decoder, fileName, keyPriority,
+ scalingFactor});
+ }
+ }
+ }
+ }
+ }
+ return argsList;
+ }
+
+ private void setUpFormat(MediaFormat format) throws Exception {
+ mDecoderFormat = new MediaFormat(format);
+ mDecoderFormat.setInteger(MediaFormat.KEY_PRIORITY, mKeyPriority);
+ mDecoderFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
+ MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
+ mOperatingRateExpected = getMaxOperatingRate(mDecoderName, mDecoderMime);
+ if (mMaxOpRateScalingFactor > 0.0f) {
+ int operatingRateToSet = (int) (mOperatingRateExpected * mMaxOpRateScalingFactor);
+ if (mMaxOpRateScalingFactor < 1.0f) {
+ mOperatingRateExpected = operatingRateToSet;
+ }
+ mDecoderFormat.setInteger(MediaFormat.KEY_OPERATING_RATE, operatingRateToSet);
+ }
+ }
+
+ /**
+ * Validates performance of hardware accelerated video decoders
+ */
+ @LargeTest
+ @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ public void testPerformanceOfHardwareVideoDecoders() throws Exception {
+ MediaFormat format = setUpDecoderInput();
+ assertNotNull("Video track not present in " + mTestFile, format);
+ mActivityRule.getActivity().waitTillSurfaceIsCreated();
+ mSurface = mActivityRule.getActivity().getSurface();
+ assertTrue("Surface created is null.", mSurface != null);
+ assertTrue("Surface created is invalid.", mSurface.isValid());
+ setUpFormat(format);
+ mDecoder = MediaCodec.createByCodecName(mDecoderName);
+ mDecoder.configure(mDecoderFormat, mSurface, null, 0);
+ mDecoder.start();
+ long start = System.currentTimeMillis();
+ doWork();
+ long finish = System.currentTimeMillis();
+ mDecoder.stop();
+ mDecoder.release();
+ assertTrue("Decoder output count is zero", mDecOutputNum > 0);
+ double achievedFps = mDecOutputNum / ((finish - start) / 1000.0);
+ String log = String.format("DecodeMime: %s, Decoder: %s, resolution: %dp, " +
+ "Key-priority: %d :: ", mDecoderMime, mDecoderName, mHeight, mKeyPriority);
+ Log.d(LOG_TAG, log + "act/exp fps: " + achievedFps + "/" + mOperatingRateExpected);
+ assertTrue("Unable to achieve the expected rate. " + log + "act/exp fps: " + achievedFps
+ + "/" + mOperatingRateExpected, achievedFps >= mOperatingRateExpected);
+ }
+
+ void doWork() {
+ MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+ while (!mSawDecOutputEOS) {
+ if (!mSawDecInputEOS) {
+ int inputBufIndex = mDecoder.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
+ if (inputBufIndex >= 0) {
+ enqueueDecoderInput(inputBufIndex);
+ }
+ }
+ int outputBufIndex = mDecoder.dequeueOutputBuffer(info, Q_DEQ_TIMEOUT_US);
+ if (outputBufIndex >= 0) {
+ dequeueDecoderOutput(outputBufIndex, info, false);
+ }
+ }
+ }
+}
diff --git a/tests/video/src/android/video/cts/CodecEncoderPerformanceTest.java b/tests/video/src/android/video/cts/CodecEncoderPerformanceTest.java
new file mode 100644
index 0000000..db95ea0
--- /dev/null
+++ b/tests/video/src/android/video/cts/CodecEncoderPerformanceTest.java
@@ -0,0 +1,250 @@
+/*
+ * 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.video.cts;
+
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecList;
+import android.media.MediaFormat;
+import android.util.Log;
+import android.view.Surface;
+
+import androidx.test.filters.LargeTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+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 static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Operating rate is expected to be met by encoder only in surface mode and not in byte buffer mode.
+ * As camera has limited frame rates and resolutions, it is not possible to test encoder
+ * operating rate alone. So we are going ahead with transcode tests as a way to verify
+ * encoder performances. This test calls decoder to decode to a surface that is coupled to encoder.
+ * This assumes encoder will not be faster than decode and expects half the operating rate
+ * to be met for encoders.
+ */
+@RunWith(Parameterized.class)
+public class CodecEncoderPerformanceTest extends CodecPerformanceTestBase {
+ private static final String LOG_TAG = CodecEncoderPerformanceTest.class.getSimpleName();
+ private static final Map<String, Float> transcodeAVCToTargetBitrateMap = new HashMap<>();
+
+ private final String mEncoderMime;
+ private final String mEncoderName;
+ private final int mBitrateAVC;
+
+ private boolean mSawEncInputEOS = false;
+ private boolean mSawEncOutputEOS = false;
+ private int mEncOutputNum = 0;
+ private MediaCodec mEncoder;
+ private MediaFormat mEncoderFormat;
+
+ // Suggested bitrate scaling factors for transcoding avc to target format.
+ static {
+ transcodeAVCToTargetBitrateMap.put(MediaFormat.MIMETYPE_VIDEO_VP8, 1.25f);
+ transcodeAVCToTargetBitrateMap.put(MediaFormat.MIMETYPE_VIDEO_AVC, 1.0f);
+ transcodeAVCToTargetBitrateMap.put(MediaFormat.MIMETYPE_VIDEO_VP9, 0.7f);
+ transcodeAVCToTargetBitrateMap.put(MediaFormat.MIMETYPE_VIDEO_HEVC, 0.6f);
+ transcodeAVCToTargetBitrateMap.put(MediaFormat.MIMETYPE_VIDEO_AV1, 0.4f);
+ }
+
+ public CodecEncoderPerformanceTest(String decoderName, String testFile, String encoderMime,
+ String encoderName, int bitrate, int keyPriority, float scalingFactor) {
+ super(decoderName, testFile, keyPriority, scalingFactor);
+ mEncoderMime = encoderMime;
+ mEncoderName = encoderName;
+ mBitrateAVC = bitrate;
+ }
+
+ 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;
+ }
+
+ private static MediaFormat setUpEncoderFormat(MediaFormat format, String mime, int bitrate) {
+ MediaFormat fmt = new MediaFormat();
+ fmt.setString(MediaFormat.KEY_MIME, mime);
+ fmt.setInteger(MediaFormat.KEY_WIDTH, format.getInteger(MediaFormat.KEY_WIDTH));
+ fmt.setInteger(MediaFormat.KEY_HEIGHT, format.getInteger(MediaFormat.KEY_HEIGHT));
+ fmt.setInteger(MediaFormat.KEY_BIT_RATE,
+ (int) (bitrate * transcodeAVCToTargetBitrateMap.getOrDefault(mime, 1.5f)));
+ fmt.setInteger(MediaFormat.KEY_FRAME_RATE,
+ format.getInteger(MediaFormat.KEY_FRAME_RATE,30));
+ fmt.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 1.0f);
+ fmt.setInteger(MediaFormat.KEY_COLOR_FORMAT,
+ MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
+ return fmt;
+ }
+
+ @Parameterized.Parameters(name = "{index}({0}_{2}_{3}_{5}_{6})")
+ public static Collection<Object[]> input() throws IOException {
+ final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
+ // Filename, Recommended AVC bitrate
+ {"crowd_run_720x480_30fps_avc.mp4", 200000},
+ {"crowd_run_1280x720_30fps_avc.mp4", 4000000},
+ {"crowd_run_1920x1080_30fps_avc.mp4", 8000000},
+ {"crowd_run_3840x2160_30fps_hevc.mp4", 20000000},
+ {"crowd_run_7680x4320_30fps_hevc.mp4", 40000000},
+ });
+ // Prepares the params list with the supported Hardware decoder, encoders in the device
+ // combined with the key priority and scaling factor
+ final List<Object[]> argsList = new ArrayList<>();
+ for (Object[] arg : exhaustiveArgsList) {
+ // Gets the format for the first video track found
+ MediaFormat format = getVideoFormat((String) arg[0]);
+ if (format == null) {
+ Log.e(LOG_TAG, "Test vector is ignored as it has no video tracks present " +
+ "in the file: " + ((String) arg[0]));
+ continue;
+ }
+ String decoderMime = format.getString(MediaFormat.KEY_MIME);
+ ArrayList<MediaFormat> formatsList = new ArrayList<>();
+ formatsList.add(format);
+ ArrayList<String> listOfDecoders = selectHardwareCodecs(decoderMime, formatsList,
+ null, false);
+ if (listOfDecoders.size() == 0) continue;
+ String decoder = listOfDecoders.get(0);
+ for (String encoderMime : getMimesOfAvailableHardwareVideoEncoders()) {
+ MediaFormat mockFmt = setUpEncoderFormat(format, encoderMime, (int) arg[1]);
+ ArrayList<MediaFormat> mockFmtList = new ArrayList<>();
+ mockFmtList.add(mockFmt);
+ ArrayList<String> listOfEncoders = selectHardwareCodecs(encoderMime, mockFmtList,
+ null, true);
+ for (String encoder : listOfEncoders) {
+ for (int keyPriority : KEY_PRIORITIES_LIST) {
+ for (float scalingFactor : SCALING_FACTORS_LIST) {
+ if (keyPriority == 1 || (scalingFactor > 0.0 && scalingFactor <= 1.0)) {
+ argsList.add(new Object[]{decoder, arg[0], encoderMime, encoder,
+ arg[1], keyPriority, scalingFactor});
+ }
+ }
+ }
+ }
+ }
+ }
+ return argsList;
+ }
+
+ private void dequeueEncoderOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+ if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+ mEncOutputNum++;
+ }
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ mSawEncOutputEOS = true;
+ }
+ mEncoder.releaseOutputBuffer(bufferIndex, false);
+ }
+
+ private void setUpFormats(MediaFormat format) throws Exception {
+ mDecoderFormat = new MediaFormat(format);
+ mDecoderFormat.setInteger(MediaFormat.KEY_PRIORITY, mKeyPriority);
+ mEncoderFormat = setUpEncoderFormat(mDecoderFormat, mEncoderMime, mBitrateAVC);
+ mEncoderFormat.setInteger(MediaFormat.KEY_PRIORITY, mKeyPriority);
+
+ double maxOperatingRateDecoder = getMaxOperatingRate(mDecoderName, mDecoderMime);
+ double maxOperatingRateEncoder = getMaxOperatingRate(mEncoderName, mEncoderMime);
+ mOperatingRateExpected = Math.min(maxOperatingRateDecoder, maxOperatingRateEncoder);
+ if (mMaxOpRateScalingFactor > 0.0f) {
+ int operatingRateToSet = (int) (mOperatingRateExpected * mMaxOpRateScalingFactor);
+ if (mMaxOpRateScalingFactor < 1.0f) {
+ mOperatingRateExpected = operatingRateToSet;
+ }
+ mDecoderFormat.setInteger(MediaFormat.KEY_OPERATING_RATE, operatingRateToSet);
+ mEncoderFormat.setInteger(MediaFormat.KEY_OPERATING_RATE, operatingRateToSet);
+ }
+ mOperatingRateExpected /= 2.0;
+ }
+
+ /**
+ * Validates performance of hardware accelerated video encoders
+ */
+ @LargeTest
+ @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
+ public void testPerformanceOfHardwareVideoEncoders() throws Exception {
+ MediaFormat format = setUpDecoderInput();
+ assertNotNull("Video track not present in " + mTestFile, format);
+ setUpFormats(format);
+ mDecoder = MediaCodec.createByCodecName(mDecoderName);
+ mEncoder = MediaCodec.createByCodecName(mEncoderName);
+ mEncoder.configure(mEncoderFormat, null, MediaCodec.CONFIGURE_FLAG_ENCODE, null);
+ Surface surface = mEncoder.createInputSurface();
+ assertTrue("Surface is not valid", surface.isValid());
+ mDecoder.configure(mDecoderFormat, surface, null, 0);
+ mDecoder.start();
+ mEncoder.start();
+ MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+ long start = System.currentTimeMillis();
+ while (!mSawEncOutputEOS) {
+ if (!mSawDecInputEOS) {
+ int inputBufIndex = mDecoder.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
+ if (inputBufIndex >= 0) {
+ enqueueDecoderInput(inputBufIndex);
+ }
+ }
+ if (!mSawDecOutputEOS) {
+ int outputBufIndex = mDecoder.dequeueOutputBuffer(info, Q_DEQ_TIMEOUT_US);
+ if (outputBufIndex >= 0) {
+ dequeueDecoderOutput(outputBufIndex, info, true);
+ }
+ }
+ if (mSawDecOutputEOS && !mSawEncInputEOS) {
+ mEncoder.signalEndOfInputStream();
+ mSawEncInputEOS = true;
+ }
+ MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
+ int outputBufferId = mEncoder.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
+ if (outputBufferId >= 0) {
+ dequeueEncoderOutput(outputBufferId, outInfo);
+ }
+ }
+ long finish = System.currentTimeMillis();
+ mEncoder.stop();
+ surface.release();
+ mEncoder.release();
+ mDecoder.stop();
+ mDecoder.release();
+ assertTrue("Encoder output count is zero", mEncOutputNum > 0);
+ double achievedFps = mEncOutputNum / ((finish - start) / 1000.0);
+ String log = String.format("DecodeMime: %s, Decoder: %s, resolution: %dp, " +
+ "EncodeMime: %s, Encoder: %s, Key-priority: %d :: ", mDecoderMime, mDecoderName,
+ mHeight, mEncoderMime, mEncoderName, mKeyPriority);
+ Log.d(LOG_TAG, log + "act/exp fps: " + achievedFps + "/" + mOperatingRateExpected);
+ assertTrue("Unable to achieve the expected rate. " + log + "act/exp fps: " + achievedFps
+ + "/" + mOperatingRateExpected, achievedFps >= mOperatingRateExpected);
+ }
+}
diff --git a/tests/video/src/android/video/cts/CodecPerformanceTestBase.java b/tests/video/src/android/video/cts/CodecPerformanceTestBase.java
new file mode 100644
index 0000000..cf4caed
--- /dev/null
+++ b/tests/video/src/android/video/cts/CodecPerformanceTestBase.java
@@ -0,0 +1,252 @@
+/*
+ * 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.video.cts;
+
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecList;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.os.Build;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+class CodecPerformanceTestBase {
+ private static final String LOG_TAG = CodecPerformanceTestBase.class.getSimpleName();
+ static final long Q_DEQ_TIMEOUT_US = 5000; // block at most 5ms while looking for io buffers
+ static final int PER_TEST_TIMEOUT_LARGE_TEST_MS = 300000;
+ static final int MIN_FRAME_COUNT = 500;
+ 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 String mInputPrefix = WorkDir.getMediaDirString();
+
+ ArrayList<MediaCodec.BufferInfo> mBufferInfos;
+ ByteBuffer mBuff;
+
+ final String mDecoderName;
+ final String mTestFile;
+ final int mKeyPriority;
+ final float mMaxOpRateScalingFactor;
+
+ String mDecoderMime;
+ int mWidth;
+ int mHeight;
+ int mFrameRate;
+
+ boolean mSawDecInputEOS = false;
+ boolean mSawDecOutputEOS = false;
+ int mDecInputNum = 0;
+ int mDecOutputNum = 0;
+ int mSampleIndex = 0;
+
+ MediaCodec mDecoder;
+ MediaFormat mDecoderFormat;
+ double mOperatingRateExpected;
+
+ static final float[] SCALING_FACTORS_LIST = new float[]{2.0f, 1.25f, 1.0f, 0.75f, 0.0f};
+ static final int[] KEY_PRIORITIES_LIST = new int[]{1, 0};
+
+ public CodecPerformanceTestBase(String decoderName, String testFile, int keyPriority,
+ float maxOpRateScalingFactor) {
+ mDecoderName = decoderName;
+ mTestFile = testFile;
+ mKeyPriority = keyPriority;
+ mMaxOpRateScalingFactor = maxOpRateScalingFactor;
+ mBufferInfos = new ArrayList<>();
+ }
+
+ static MediaFormat getVideoFormat(String filePath) throws IOException {
+ final String input = mInputPrefix + filePath;
+ MediaExtractor extractor = new MediaExtractor();
+ extractor.setDataSource(input);
+ for (int trackID = 0; trackID < extractor.getTrackCount(); trackID++) {
+ MediaFormat format = extractor.getTrackFormat(trackID);
+ if (format.getString(MediaFormat.KEY_MIME).startsWith("video/")) {
+ extractor.release();
+ return format;
+ }
+ }
+ extractor.release();
+ return null;
+ }
+
+ static ArrayList<String> selectCodecs(String mime, ArrayList<MediaFormat> formats,
+ String[] features, boolean isEncoder) {
+ return selectCodecs(mime, formats, features, isEncoder, SELECT_ALL);
+ }
+
+ static ArrayList<String> selectHardwareCodecs(String mime, ArrayList<MediaFormat> formats,
+ String[] features, boolean isEncoder) {
+ return selectCodecs(mime, formats, features, isEncoder, SELECT_HARDWARE);
+ }
+
+ static ArrayList<String> selectCodecs(String mime, ArrayList<MediaFormat> formats,
+ String[] features, boolean isEncoder, int selectCodecOption) {
+ MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
+ ArrayList<String> listOfCodecs = new ArrayList<>();
+ for (MediaCodecInfo codecInfo : codecInfos) {
+ if (codecInfo.isEncoder() != isEncoder) continue;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && codecInfo.isAlias()) continue;
+ if (selectCodecOption == SELECT_HARDWARE && !codecInfo.isHardwareAccelerated())
+ continue;
+ else if (selectCodecOption == SELECT_SOFTWARE && !codecInfo.isSoftwareOnly())
+ continue;
+ String[] types = codecInfo.getSupportedTypes();
+ for (String type : types) {
+ if (type.equalsIgnoreCase(mime)) {
+ boolean isOk = true;
+ MediaCodecInfo.CodecCapabilities codecCapabilities =
+ codecInfo.getCapabilitiesForType(type);
+ if (formats != null) {
+ for (MediaFormat format : formats) {
+ if (!codecCapabilities.isFormatSupported(format)) {
+ isOk = false;
+ break;
+ }
+ }
+ }
+ if (features != null) {
+ for (String feature : features) {
+ if (!codecCapabilities.isFeatureSupported(feature)) {
+ isOk = false;
+ break;
+ }
+ }
+ }
+ if (isOk) listOfCodecs.add(codecInfo.getName());
+ }
+ }
+ }
+ return listOfCodecs;
+ }
+
+ MediaFormat setUpDecoderInput() throws IOException {
+ final String input = mInputPrefix + mTestFile;
+ MediaExtractor extractor = new MediaExtractor();
+ extractor.setDataSource(input);
+ for (int trackID = 0; trackID < extractor.getTrackCount(); trackID++) {
+ MediaFormat format = extractor.getTrackFormat(trackID);
+ if (format.getString(MediaFormat.KEY_MIME).startsWith("video/")) {
+ extractor.selectTrack(trackID);
+ File file = new File(input);
+ int bufferSize = ((int) file.length()) << 1;
+ mBuff = ByteBuffer.allocate(bufferSize);
+ int offset = 0;
+ long maxPTS = 0;
+ while (true) {
+ MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
+ bufferInfo.size = extractor.readSampleData(mBuff, offset);
+ if (bufferInfo.size < 0) break;
+ bufferInfo.offset = offset;
+ bufferInfo.presentationTimeUs = extractor.getSampleTime();
+ maxPTS = Math.max(maxPTS, bufferInfo.presentationTimeUs);
+ int flags = extractor.getSampleFlags();
+ bufferInfo.flags = 0;
+ if ((flags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
+ bufferInfo.flags |= MediaCodec.BUFFER_FLAG_KEY_FRAME;
+ }
+ mBufferInfos.add(bufferInfo);
+ extractor.advance();
+ offset += bufferInfo.size;
+ }
+
+ // If the clip doesn't have sufficient frames, loopback by copying bufferInfos
+ // from the start of the list and incrementing the timestamp.
+ int actualBufferInfosCount = mBufferInfos.size();
+ long ptsOffset;
+ while (mBufferInfos.size() < MIN_FRAME_COUNT) {
+ ptsOffset = maxPTS + 1000000L;
+ for (int i = 0; i < actualBufferInfosCount; i++) {
+ MediaCodec.BufferInfo tmpBufferInfo = mBufferInfos.get(i);
+ MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
+ bufferInfo.set(tmpBufferInfo.offset, tmpBufferInfo.size,
+ ptsOffset + tmpBufferInfo.presentationTimeUs,
+ tmpBufferInfo.flags);
+ maxPTS = Math.max(maxPTS, bufferInfo.presentationTimeUs);
+ mBufferInfos.add(bufferInfo);
+ }
+ }
+ MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
+ bufferInfo.set(0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+ mBufferInfos.add(bufferInfo);
+ mDecoderMime = format.getString(MediaFormat.KEY_MIME);
+ mWidth = format.getInteger(MediaFormat.KEY_WIDTH);
+ mHeight = format.getInteger(MediaFormat.KEY_HEIGHT);
+ mFrameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE, 30);
+ extractor.release();
+ return format;
+ }
+ }
+ extractor.release();
+ fail("No video track found in file: " + mTestFile);
+ return null;
+ }
+
+ int getMaxOperatingRate(String codecName, String mime) throws Exception {
+ MediaCodec codec = MediaCodec.createByCodecName(codecName);
+ MediaCodecInfo mediaCodecInfo = codec.getCodecInfo();
+ List<MediaCodecInfo.VideoCapabilities.PerformancePoint> pps = mediaCodecInfo
+ .getCapabilitiesForType(mime).getVideoCapabilities()
+ .getSupportedPerformancePoints();
+ assertTrue(pps.size() > 0);
+ MediaCodecInfo.VideoCapabilities.PerformancePoint cpp =
+ new MediaCodecInfo.VideoCapabilities.PerformancePoint(mWidth, mHeight, mFrameRate);
+ int macroblocks = cpp.getMaxMacroBlocks();
+ int maxOperatingRate = -1;
+ for (MediaCodecInfo.VideoCapabilities.PerformancePoint pp : pps) {
+ if (pp.covers(cpp)) {
+ maxOperatingRate = Math.max(Math.min(pp.getMaxFrameRate(),
+ (int) pp.getMaxMacroBlockRate() / macroblocks), maxOperatingRate);
+ }
+ }
+ codec.release();
+ assertTrue(maxOperatingRate != -1);
+ return maxOperatingRate;
+ }
+
+ void enqueueDecoderInput(int bufferIndex) {
+ MediaCodec.BufferInfo info = mBufferInfos.get(mSampleIndex++);
+ if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+ ByteBuffer dstBuf = mDecoder.getInputBuffer(bufferIndex);
+ dstBuf.put(mBuff.array(), info.offset, info.size);
+ mDecInputNum++;
+ }
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ mSawDecInputEOS = true;
+ }
+ mDecoder.queueInputBuffer(bufferIndex, 0, info.size, info.presentationTimeUs, info.flags);
+ }
+
+ void dequeueDecoderOutput(int bufferIndex, MediaCodec.BufferInfo info, boolean render) {
+ if (info.size > 0) {
+ mDecOutputNum++;
+ }
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ mSawDecOutputEOS = true;
+ }
+ mDecoder.releaseOutputBuffer(bufferIndex, render);
+ }
+}
diff --git a/tests/video/src/android/video/cts/CodecTestActivity.java b/tests/video/src/android/video/cts/CodecTestActivity.java
new file mode 100644
index 0000000..89c669d
--- /dev/null
+++ b/tests/video/src/android/video/cts/CodecTestActivity.java
@@ -0,0 +1,86 @@
+/*
+ * 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.video.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class CodecTestActivity extends Activity implements SurfaceHolder.Callback {
+ private static final String LOG_TAG = CodecTestActivity.class.getSimpleName();
+ private SurfaceView mSurfaceView;
+ private SurfaceHolder mHolder;
+ private Surface mSurface;
+ private final Lock mLock = new ReentrantLock();
+ private final Condition mCondition = mLock.newCondition();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.media_decoder_surface_layout);
+ mSurfaceView = findViewById(R.id.surface);
+ mHolder = mSurfaceView.getHolder();
+ mHolder.addCallback(this);
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ Log.v(LOG_TAG, "surface created");
+ mLock.lock();
+ mSurface = mHolder.getSurface();
+ mLock.unlock();
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ Log.v(LOG_TAG, "surface changed " + format + " " + width + " " + height);
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ Log.v(LOG_TAG, "surface deleted");
+ mLock.lock();
+ mSurface = null;
+ mLock.unlock();
+ }
+
+ public void waitTillSurfaceIsCreated() throws InterruptedException {
+ final long mWaitTimeMs = 1000;
+ final int retries = 3;
+ mLock.lock();
+ final long start = SystemClock.elapsedRealtime();
+ while ((SystemClock.elapsedRealtime() - start) < (retries * mWaitTimeMs) &&
+ mSurface == null) {
+ mCondition.await(mWaitTimeMs, TimeUnit.MILLISECONDS);
+ }
+ mLock.unlock();
+ if (mSurface == null) {
+ throw new InterruptedException("Taking too long to attach a SurfaceView to a window.");
+ }
+ }
+
+ public Surface getSurface() { return mSurface; }
+}
diff --git a/tests/video/src/android/video/cts/WorkDir.java b/tests/video/src/android/video/cts/WorkDir.java
new file mode 100644
index 0000000..c69e0f0
--- /dev/null
+++ b/tests/video/src/android/video/cts/WorkDir.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.video.cts;
+
+import android.os.Environment;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Assert;
+
+import java.io.File;
+
+class WorkDir {
+ private static final String MEDIA_PATH_INSTR_ARG_KEY = "media-path";
+ static private final File getTopDir() {
+ Assert.assertEquals(Environment.getExternalStorageState(), Environment.MEDIA_MOUNTED);
+ return Environment.getExternalStorageDirectory();
+ }
+ static private final String getTopDirString() {
+ return (getTopDir().getAbsolutePath() + File.separator);
+ }
+ static final String getMediaDirString() {
+ android.os.Bundle bundle = InstrumentationRegistry.getArguments();
+ String mediaDirString = bundle.getString(MEDIA_PATH_INSTR_ARG_KEY);
+ if (mediaDirString != null) {
+ // user has specified the mediaDirString via instrumentation-arg
+ return mediaDirString + ((mediaDirString.endsWith("/")) ? "" : "/");
+ } else {
+ return (getTopDirString() + "test/CtsVideoTestCases-1.1/");
+ }
+ }
+}
diff --git a/tools/cts-device-info/Android.mk b/tools/cts-device-info/Android.mk
index cc67eee..2fcbd6b 100644
--- a/tools/cts-device-info/Android.mk
+++ b/tools/cts-device-info/Android.mk
@@ -38,6 +38,8 @@
com.android.cts.deviceinfo.VulkanDeviceInfo
LOCAL_PACKAGE_NAME := CtsDeviceInfo
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts general-tests sts mts vts
diff --git a/tools/cts-tradefed/OWNERS b/tools/cts-tradefed/OWNERS
index 3842024..06936014 100644
--- a/tools/cts-tradefed/OWNERS
+++ b/tools/cts-tradefed/OWNERS
@@ -14,4 +14,5 @@
per-file cts-meerkat.xml = alanstokes@google.com, brufino@google.com, lus@google.com, rickywai@google.com
per-file cts-on-csi*.xml = ycchen@google.com, hsinyichen@google.com, tyanh@google.com
per-file csi-*.xml = ycchen@google.com, hsinyichen@google.com, tyanh@google.com
+per-file cts-on-gsi*.xml = bettyzhou@google.com, ycchen@google.com, hsinyichen@google.com, tyanh@google.com
diff --git a/tools/cts-tradefed/etc/cts-tradefed b/tools/cts-tradefed/etc/cts-tradefed
index 117f4cd..b9d5547 100755
--- a/tools/cts-tradefed/etc/cts-tradefed
+++ b/tools/cts-tradefed/etc/cts-tradefed
@@ -55,12 +55,6 @@
RDBG_FLAG=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=${TF_DEBUG_PORT}
fi
-JAVA_BINARY=${CTS_ROOT}/android-cts/jdk/bin/java
-
-if [ ! -f "${JAVA_BINARY}" ]; then
- JAVA_BINARY=java
-fi
-
# get OS
HOST=`uname`
if [ "$HOST" == "Linux" ]; then
@@ -92,6 +86,14 @@
CTS_ROOT="$(dirname $(realpath $0))/../.."
fi;
+if [ -z ${JAVA_BINARY} ]; then
+ JAVA_BINARY=${CTS_ROOT}/android-cts/jdk/bin/java
+fi;
+
+if [ ! -f "${JAVA_BINARY}" ]; then
+ JAVA_BINARY=java
+fi
+
JAR_DIR=${CTS_ROOT}/android-cts/tools
for JAR in ${JAR_DIR}/*.jar; do
diff --git a/tools/cts-tradefed/res/config/cts-foldable.xml b/tools/cts-tradefed/res/config/cts-foldable.xml
index 1a3e256..1b6b9bb 100644
--- a/tools/cts-tradefed/res/config/cts-foldable.xml
+++ b/tools/cts-tradefed/res/config/cts-foldable.xml
@@ -23,4 +23,8 @@
<!-- CTS tests to be excluded in this plan-->
<option name="compatibility:exclude-filter" value="CtsDeqpTestCases" />
+ <!-- b/178344549: CtsCameraTestCases failures due to covered lenses in folded mode-->
+ <option name="compatibility:exclude-filter" value="CtsCameraTestCases android.hardware.camera2.cts.BurstCaptureTest#testJpegBurst" />
+ <option name="compatibility:exclude-filter" value="CtsCameraTestCases[instant] android.hardware.camera2.cts.BurstCaptureTest#testJpegBurst" />
+
</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-on-aosp-exclude.xml b/tools/cts-tradefed/res/config/cts-on-aosp-exclude.xml
index a9d2ac5..9b6250d 100644
--- a/tools/cts-tradefed/res/config/cts-on-aosp-exclude.xml
+++ b/tools/cts-tradefed/res/config/cts-on-aosp-exclude.xml
@@ -80,7 +80,6 @@
<!-- b/73727333: CtsSystemUiTestCases failure flaky -->
<option name="compatibility:exclude-filter" value="CtsSystemUiTestCases android.systemui.cts.LightBarTests#testLightNavigationBar" />
- <option name="compatibility:exclude-filter" value="CtsSystemUiTestCases android.systemui.cts.LightBarThemeTest#testNavigationBarDivider" />
<!-- b/80388296: CtsDevicePolicyManagerTestCases failure flaky -->
<option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedManagedProfileOwnerTest#testDisallowAutofill_allowed" />
@@ -91,21 +90,7 @@
<option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedManagedProfileOwnerTest#testPermissionPolicy" />
<option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedManagedProfileOwnerTest#testSuspendPackage" />
- <!-- b/80407835: CtsServicesHostTestCases failure flaky -->
- <option name="compatibility:exclude-filter" value="CtsServicesHostTestCases android.server.cts.KeyguardTests#testDialogShowWhenLockedActivity" />
- <option name="compatibility:exclude-filter" value="CtsServicesHostTestCases android.server.cts.KeyguardTests#testTranslucentShowWhenLockedActivity" />
-
- <!-- b/80284482: Flaky tests -->
- <option name="compatibility:exclude-filter" value="CtsAlarmManagerTestCases android.alarmmanager.cts.AppStandbyTests#testAllowWhileIdleAlarms" />
- <option name="compatibility:exclude-filter" value="CtsAlarmManagerTestCases android.alarmmanager.cts.AppStandbyTests#testBucketUpgradeToNoDelay" />
- <option name="compatibility:exclude-filter" value="CtsAlarmManagerTestCases android.alarmmanager.cts.AppStandbyTests#testBucketUpgradeToSmallerDelay" />
- <option name="compatibility:exclude-filter" value="CtsAlarmManagerTestCases android.alarmmanager.cts.AppStandbyTests#testFrequentDelay" />
- <option name="compatibility:exclude-filter" value="CtsAlarmManagerTestCases android.alarmmanager.cts.AppStandbyTests#testRareDelay" />
- <option name="compatibility:exclude-filter" value="CtsAlarmManagerTestCases android.alarmmanager.cts.AppStandbyTests#testWorkingSetDelay" />
-
<!-- b/110260628: A confirmed GSI incompatibility (waiver) -->
- <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.DeviceOwnerTest#testCreateAndManageUser_DontSkipSetupWizard" />
- <option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.DeviceOwnerTest#testSecurityLoggingWithSingleUser" />
<option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedDeviceOwnerTest#testKeyManagement" />
<option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedProfileOwnerTest#testKeyManagement" />
<option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.MixedManagedProfileOwnerTest#testKeyManagement" />
@@ -128,15 +113,6 @@
<option name="compatibility:exclude-filter" value="CtsOsTestCases android.os.cts.BuildTest#testIsSecureUserBuild" />
<option name="compatibility:exclude-filter" value="CtsOsTestCases android.os.cts.BuildVersionTest#testBuildFingerprint" />
- <!-- b/110405126: CtsPermissionTestCases flaky (due to SIM card setting) -->
- <option name="compatibility:exclude-filter" value="CtsPermissionTestCases android.permission.cts.TelephonyManagerPermissionTest#testGetDeviceId" />
- <option name="compatibility:exclude-filter" value="CtsPermissionTestCases android.permission.cts.TelephonyManagerPermissionTest#testGetImei" />
- <option name="compatibility:exclude-filter" value="CtsPermissionTestCases android.permission.cts.TelephonyManagerPermissionTest#testGetLine1Number" />
- <option name="compatibility:exclude-filter" value="CtsPermissionTestCases android.permission.cts.TelephonyManagerPermissionTest#testGetSimSerialNumber" />
- <option name="compatibility:exclude-filter" value="CtsPermissionTestCases android.permission.cts.TelephonyManagerPermissionTest#testGetSubscriberId" />
- <option name="compatibility:exclude-filter" value="CtsPermissionTestCases android.permission.cts.TelephonyManagerPermissionTest#testSetDataEnabled" />
- <option name="compatibility:exclude-filter" value="CtsPermissionTestCases android.permission.cts.TelephonyManagerPermissionTest#testVoiceMailNumber" />
-
<!-- b/111967702: CtsSecurityTestCases irrelevant test cases -->
<option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.BannedFilesTest#testNoSu" />
<option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.BannedFilesTest#testNoSuInPath" />
diff --git a/tools/cts-tradefed/res/config/cts-on-gsi-exclude-non-hal.xml b/tools/cts-tradefed/res/config/cts-on-gsi-exclude-non-hal.xml
new file mode 100644
index 0000000..03d6e41
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-on-gsi-exclude-non-hal.xml
@@ -0,0 +1,210 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Excluded non-HAL tests from cts-on-gsi">
+
+ <!-- b/182542290 Exclude non-HAL tests from cts-on-gsi -->
+ <option name="compatibility:exclude-filter" value="CtsAbiOverrideHostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceSdk29TestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAccountManagerTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAccountsHostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsActivityManagerBackgroundActivityTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAdminPackageInstallerTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAdminTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAndroidAppTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAndroidTestBase28ApiSignatureTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAndroidTestBaseCurrentApiSignatureTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAndroidTestMockCurrentApiSignatureTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAndroidTestRunnerCurrentApiSignatureTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsApacheHttpLegacy27ApiSignatureTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsApacheHttpLegacyCurrentApiSignatureTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsApacheHttpLegacyUsesLibraryApiSignatureTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsApexTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAppBindingHostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAppCompatHostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAppComponentFactoryTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAppEnumerationTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAppExitTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAppIntegrityDeviceTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAppOpsTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAtraceHostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsAttentionServiceDeviceTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsBionicAppTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsBionicTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsBootStatsTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsCalendarcommon2TestCases" />
+ <option name="compatibility:exclude-filter" value="CtsCalendarProviderTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsCodePathHostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsCompilationTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsContactsProviderTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsContactsProviderWipe" />
+ <option name="compatibility:exclude-filter" value="CtsContentCaptureServiceTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsContentTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsControlsDeviceTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsCppToolsTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsCurrentApiSignatureTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsDatabaseTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsHiddenApiKillswitchDebugClassTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsHiddenApiKillswitchWildcardTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJdwpTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJdwpTunnelHostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJniTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiAttachingHostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiAttachingTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRedefineClassesHostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1900HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1901HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1902HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1903HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1904HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1906HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1907HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1908HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1909HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1910HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1911HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1912HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1913HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1914HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1915HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1916HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1917HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1920HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1921HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1922HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1923HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1924HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1925HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1926HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1927HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1928HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1930HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1931HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1932HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1933HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1934HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1936HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1937HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1939HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1941HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1942HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1943HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1953HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1958HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1962HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1967HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1968HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1969HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1970HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1971HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1974HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1975HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1976HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1977HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1978HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1979HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1981HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1982HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1983HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1984HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1988HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1989HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1990HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1991HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1992HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1994HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1995HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1996HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1997HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1998HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest1999HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest2001HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest2002HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest2003HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest2004HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest2005HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest2006HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest2007HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest902HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest903HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest904HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest905HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest906HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest907HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest908HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest910HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest911HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest912HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest913HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest914HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest915HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest917HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest918HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest919HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest920HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest922HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest923HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest924HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest926HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest927HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest928HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest930HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest931HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest932HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest940HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest942HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest944HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest945HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest947HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest951HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest982HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest983HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest984HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest985HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest986HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest988HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest989HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest990HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest991HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest992HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest993HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest994HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest995HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest996HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiRunTest997HostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiTaggingHostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsJvmtiTrackingHostTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsLegacyNotification20TestCases" />
+ <option name="compatibility:exclude-filter" value="CtsLegacyNotification27TestCases" />
+ <option name="compatibility:exclude-filter" value="CtsLegacyNotification28TestCases" />
+ <option name="compatibility:exclude-filter" value="CtsLegacyNotification29TestCases" />
+ <option name="compatibility:exclude-filter" value="CtsLocationNoneTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsNetTestCasesInternetPermission" />
+ <option name="compatibility:exclude-filter" value="CtsOsTestCases android.os.cts.StrictModeTest" />
+ <option name="compatibility:exclude-filter" value="CtsPackageInstallAppOpDefaultTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsPackageInstallAppOpDeniedTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsPackageInstallerTapjackingTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsPackageInstallTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsPackageUninstallTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsPackageWatchdogTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsSimpleCpuTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsSoundTriggerTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsSystemIntentTestCases" />
+ <option name="compatibility:exclude-filter" value="CtsTelephony3TestCases" />
+ <option name="compatibility:exclude-filter" value="CtsThemeDeviceTestCases" />
+
+</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 930bc4d..fa286bc 100644
--- a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
+++ b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
@@ -53,4 +53,16 @@
<!-- No SettingsIntelligence -->
<option name="compatibility:exclude-filter" value="CtsContentTestCases android.content.cts.AvailableIntentsTest#testSettingsSearchIntent" />
+ <!-- No AccessibilityService -->
+ <option name="compatibility:exclude-filter" value="CtsAccessibilityServiceTestCases android.accessibilityservice.cts" />
+
+ <!-- No Statsd -->
+ <option name="compatibility:exclude-filter" value="CtsStatsdHostTestCases" />
+
+ <!-- b/183654427 Remove CtsTelecomTestCases from cts-on-gsi -->
+ <option name="compatibility:exclude-filter" value="CtsTelecomTestCases" />
+
+ <!-- b/183659262 Remove CtsPreferenceTestCases from cts-on-gsi -->
+ <option name="compatibility:exclude-filter" value="CtsPreferenceTestCases" />
+
</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-on-gsi.xml b/tools/cts-tradefed/res/config/cts-on-gsi.xml
index be89e79..327ba547 100644
--- a/tools/cts-tradefed/res/config/cts-on-gsi.xml
+++ b/tools/cts-tradefed/res/config/cts-on-gsi.xml
@@ -17,6 +17,7 @@
<include name="cts-on-aosp" />
<include name="cts-on-gsi-exclude" />
+ <include name="cts-on-gsi-exclude-non-hal" />
<option name="plan" value="cts-on-gsi" />
diff --git a/tools/cts-tradefed/res/config/cts-sim-include.xml b/tools/cts-tradefed/res/config/cts-sim-include.xml
index 8f093a7..e9a69ea 100644
--- a/tools/cts-tradefed/res/config/cts-sim-include.xml
+++ b/tools/cts-tradefed/res/config/cts-sim-include.xml
@@ -30,6 +30,7 @@
<option name="compatibility:include-filter" value="CtsSecureElementAccessControlTestCases1" />
<option name="compatibility:include-filter" value="CtsSecureElementAccessControlTestCases2" />
<option name="compatibility:include-filter" value="CtsSecureElementAccessControlTestCases3" />
+ <option name="compatibility:include-filter" value="CtsSimPhonebookProviderTestCases" />
<option name="compatibility:include-filter" value="CtsSimRestrictedApisTestCases" />
<option name="compatibility:include-filter" value="CtsStatsdHostTestCases" />
<option name="compatibility:include-filter" value="CtsTelecomTestCases" />
diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/DupFileTest.java b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/DupFileTest.java
deleted file mode 100644
index c4055ef..0000000
--- a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/DupFileTest.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * 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.
- */
-package com.android.compatibility.common.tradefed.presubmit;
-
-import static org.junit.Assert.fail;
-
-import com.android.tradefed.config.ConfigurationException;
-
-import com.google.common.collect.ImmutableSet;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-
-/**
- * Test to check for duplicate files in different jars and prevent the same dependencies of being
- * included several time (which might result in version conflicts).
- */
-@RunWith(JUnit4.class)
-public class DupFileTest {
-
- // We ignore directories part of the common java and google packages.
- private static final String[] IGNORE_DIRS =
- new String[] {
- "android/",
- "javax/annotation/",
- "com/google/protobuf/",
- "kotlin/",
- "perfetto/protos/"
- };
- // Temporarily exclude some Tradefed jar while we work on unbundling them.
- private static final Set<String> IGNORE_JARS =
- ImmutableSet.of("tradefed-no-fwk.jar", "tradefed-test-framework.jar",
- "compatibility-tradefed.jar");
-
- /** test if there are duplicate files in different jars. */
- @Test
- public void testDupFilesExist() throws Exception {
- // Get list of jars.
- List<File> jars = getListOfBuiltJars();
-
- // Create map of files to jars.
- Map<String, List<String>> filesToJars = getMapOfFilesAndJars(jars);
-
- // Check if there are any files with the same name in diff jars.
- int dupedFiles = 0;
- StringBuilder dupedFilesSummary = new StringBuilder();
- for (Map.Entry<String, List<String>> entry : filesToJars.entrySet()) {
- String file = entry.getKey();
- List<String> jarFiles = entry.getValue();
-
- if (jarFiles.size() != 1) {
- dupedFiles++;
- dupedFilesSummary.append(file + ": " + jarFiles.toString() + "\n");
- }
- }
-
- if (dupedFiles != 0) {
- fail(
- String.format(
- "%d files are duplicated in different jars:\n%s",
- dupedFiles, dupedFilesSummary.toString()));
- }
- }
-
- /** Create map of file to jars */
- private Map<String, List<String>> getMapOfFilesAndJars(List<File> jars) throws IOException {
- Map<String, List<String>> map = new LinkedHashMap<String, List<String>>();
- JarFile jarFile;
- List<String> jarFileList;
- // Map all the files from all the jars.
- for (File jar : jars) {
- if (IGNORE_JARS.contains(jar.getName())) {
- continue;
- }
- jarFile = new JarFile(jar);
- jarFileList = getListOfFiles(jarFile);
- jarFile.close();
-
- // Add in the jar file to the map.
- for (String file : jarFileList) {
- if (!map.containsKey(file)) {
- map.put(file, new LinkedList<String>());
- }
-
- map.get(file).add(jar.getName());
- }
- }
- return map;
- }
-
- /** Get the list of jars specified in the path. */
- private List<File> getListOfBuiltJars() throws ConfigurationException {
- String classpathStr = System.getProperty("java.class.path");
- if (classpathStr == null) {
- throw new ConfigurationException(
- "Could not find the classpath property: java.class.path");
- }
- List<File> listOfJars = new ArrayList<File>();
- for (String jar : classpathStr.split(":")) {
- File jarFile = new File(jar);
- if (jarFile.exists()) {
- listOfJars.add(jarFile);
- }
- }
- return listOfJars;
- }
-
- /** Return the list of files in the jar. */
- private List<String> getListOfFiles(JarFile jar) {
- List<String> files = new ArrayList<String>();
- Enumeration<JarEntry> e = jar.entries();
- while (e.hasMoreElements()) {
- JarEntry entry = e.nextElement();
- String filename = entry.getName();
- if (checkThisFile(filename)) {
- files.add(filename);
- }
- }
- return files;
- }
-
- /** Check if we should add this file to list of files. We only want to check for classes. */
- private Boolean checkThisFile(String filename) {
- if (!filename.endsWith(".class")) {
- return false;
- }
-
- for (String skipDir : IGNORE_DIRS) {
- if (filename.startsWith(skipDir)) {
- return false;
- }
- }
-
- return true;
- }
-}
diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/tradefed/CtsUnitTests.java b/tools/cts-tradefed/tests/src/com/android/compatibility/tradefed/CtsUnitTests.java
index d989014..821491d 100644
--- a/tools/cts-tradefed/tests/src/com/android/compatibility/tradefed/CtsUnitTests.java
+++ b/tools/cts-tradefed/tests/src/com/android/compatibility/tradefed/CtsUnitTests.java
@@ -17,7 +17,6 @@
import com.android.compatibility.common.tradefed.presubmit.ApkPackageNameCheck;
import com.android.compatibility.common.tradefed.presubmit.CtsConfigLoadingTest;
-import com.android.compatibility.common.tradefed.presubmit.DupFileTest;
import com.android.compatibility.common.tradefed.presubmit.PresubmitSetupValidation;
import com.android.compatibility.common.tradefed.presubmit.ValidateTestsAbi;
@@ -38,7 +37,6 @@
// presubmit
ApkPackageNameCheck.class,
CtsConfigLoadingTest.class,
- DupFileTest.class,
PresubmitSetupValidation.class,
ValidateTestsAbi.class,
})
diff --git a/tools/incremental-cts/OWNERS b/tools/incremental-cts/OWNERS
new file mode 100644
index 0000000..3f054e0
--- /dev/null
+++ b/tools/incremental-cts/OWNERS
@@ -0,0 +1,3 @@
+yichunli@google.com
+fdeng@google.com
+normancheung@google.com
diff --git a/tools/incremental-cts/README.md b/tools/incremental-cts/README.md
new file mode 100644
index 0000000..c5cb03d
--- /dev/null
+++ b/tools/incremental-cts/README.md
@@ -0,0 +1,24 @@
+# Note
+incremental-cts is an EXPERIMENTAL project. It's for analysis purpose only and is NOT meant to be used for approval runs.
+
+# Examples
+
+## Generate dEQP dependency
+This command will generate a dEQP dependency file named `dEQP-dependency.txt`:
+```
+python3 incremental_deqp.py -s device_serial_number -t /path/to/test_resources
+--generate_deps_only
+```
+
+## Check if current build could skip dEQP
+
+Before running this command, please create `extra_deqp_dependency.txt` file and
+copy it to test resources directory. `extra_deqp_dependency.txt` includes the
+dEQP dependencies that can't be detected by this tool such as firmwares.
+```
+python3 incremental_deqp.py -s device_serial_number -t /path/to/test_resources
+-b /path/to/target_file
+```
+
+Target file is an build artifact produced by Android build system, e.g.
+https://ci.android.com/builds/submitted/7230538/aosp_arm64-userdebug/latest/aosp_arm64-target_files-7230538.zip
diff --git a/tools/incremental-cts/abstract_build_file_handler.py b/tools/incremental-cts/abstract_build_file_handler.py
new file mode 100644
index 0000000..321deda
--- /dev/null
+++ b/tools/incremental-cts/abstract_build_file_handler.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Abstract class that reads build file."""
+
+class AbstractBuildFileHandler(object):
+ """Build file handler interface."""
+
+ def __init__(self, build_file):
+ self.build_file = build_file
+
+ def get_file_hash(self, file_names, hash_func=None):
+ """Get hash value of file's content.
+
+ Args:
+ file_names: list of file names inside build file, the format should be
+ consistent with the file in device, e.g. /system/build.prop.
+ hash_func: optional hash function.
+ Returns:
+ A dictionary where key is file name and value is hash value of its content.
+ """
+ raise NotImplementedError('You need to implement get_file_hash function.')
+
+ def get_system_fingerprint(self):
+ """Get build fingerprint in SYSTEM partition.
+
+ Fingerprint format: $(BRAND)/$(PRODUCT)/$(DEVICE)/$(BOARD):
+ $(VERSION.RELEASE)/$(ID)/$(VERSION.INCREMENTAL):$(TYPE)/$(TAGS)
+
+ Returns:
+ String of build fingerprint.
+ """
+ raise NotImplementedError('You need to implement get_system_fingerprint function.')
diff --git a/tools/incremental-cts/custom_build_file_handler.py b/tools/incremental-cts/custom_build_file_handler.py
new file mode 100644
index 0000000..7065ed7
--- /dev/null
+++ b/tools/incremental-cts/custom_build_file_handler.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Implement this class to read your build file."""
+
+from abstract_build_file_handler import *
+
+class CustomBuildFileHandler(AbstractBuildFileHandler):
+ """Custom handler."""
+
+ def __init__(self, build_file):
+ super().__init__(build_file)
+
+ def get_file_hash(self, file_names, hash_func=None):
+ """See base class."""
+ raise NotImplementedError('You need to implement get_file_hash function.')
+
+ def get_system_fingerprint(self):
+ """See base class."""
+ raise NotImplementedError('You need to implement get_system_fingerprint function.')
+
diff --git a/tools/incremental-cts/incremental_deqp.py b/tools/incremental-cts/incremental_deqp.py
new file mode 100644
index 0000000..0ff7a27
--- /dev/null
+++ b/tools/incremental-cts/incremental_deqp.py
@@ -0,0 +1,712 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Incremental dEQP
+
+This script will run a subset of dEQP test on device to get dEQP dependency.
+
+Usage 1: Compare with a base build to check if any dEQP dependency has
+changed. Output a decision if dEQP could be skipped, and a cts-tradefed
+command to be used based on the decision.
+
+python3 incremental_deqp.py -s [device serial] -t [test directory] -b
+[base build target file] -c [current build target file]
+
+Usage 2: Generate a file containing a list of dEQP dependencies for the
+build on device.
+
+python3 incremental_deqp.py -s [device serial] -t [test directory]
+--generate_deps_only
+
+"""
+import argparse
+import importlib
+import json
+import logging
+import os
+import pkgutil
+import re
+import subprocess
+import tempfile
+import time
+import uuid
+from target_file_handler import TargetFileHandler
+from custom_build_file_handler import CustomBuildFileHandler
+from zipfile import ZipFile
+
+
+DEFAULT_CTS_XML = ('<?xml version="1.0" encoding="utf-8"?>\n'
+ '<configuration description="Runs CTS from a pre-existing CTS installation">\n'
+ ' <include name="cts-common" />\n'
+ ' <include name="cts-exclude" />\n'
+ ' <include name="cts-exclude-instant" />\n'
+ ' <option name="enable-token-sharding" '
+ 'value="true" />\n'
+ ' <option name="plan" value="cts" />\n'
+ '</configuration>\n')
+
+INCREMENTAL_DEQP_XML = ('<?xml version="1.0" encoding="utf-8"?>\n'
+ '<configuration description="Runs CTS with incremental dEQP">\n'
+ ' <include name="cts-common" />\n'
+ ' <include name="cts-exclude" />\n'
+ ' <include name="cts-exclude-instant" />\n'
+ ' <option name="enable-token-sharding" '
+ 'value="true" />\n'
+ ' <option name="compatibility:exclude-filter" '
+ 'value="CtsDeqpTestCases" />\n'
+ ' <option name="plan" value="cts" />\n'
+ '</configuration>\n')
+
+REPORT_FILENAME = 'incremental_dEQP_report.json'
+
+logger = logging.getLogger()
+
+
+class AtsError(Exception):
+ """Error when running incremental dEQP with Android Test Station"""
+ pass
+
+class AdbError(Exception):
+ """Error when running adb command."""
+ pass
+
+class TestError(Exception):
+ """Error when running dEQP test."""
+ pass
+
+class TestResourceError(Exception):
+ """Error with test resource. """
+ pass
+
+class BuildHelper(object):
+ """Helper class for analyzing build."""
+
+ def __init__(self, custom_handler=False):
+ """Init BuildHelper.
+
+ Args:
+ custom_handler: use custom build handler.
+ """
+ self._build_file_handler = TargetFileHandler
+ if custom_handler:
+ self._build_file_handler = CustomBuildFileHandler
+
+
+ def compare_base_build_with_current_build(self, deqp_deps, current_build_file,
+ base_build_file):
+ """Compare the difference of current build and base build with dEQP dependency.
+
+ If the difference doesn't involve dEQP dependency, current build could skip dEQP test if
+ base build has passed test.
+
+ Args:
+ deqp_deps: a set of dEQP dependency.
+ current_build_file: current build's file name.
+ base_build_file: base build's file name.
+ Returns:
+ True if current build could skip dEQP, otherwise False.
+ Dictionary of changed dependencies and their details.
+ """
+ print('Comparing base build and current build...')
+ current_build_handler = self._build_file_handler(current_build_file)
+ current_build_hash = current_build_handler.get_file_hash(deqp_deps)
+
+ base_build_handler = self._build_file_handler(base_build_file)
+ base_build_hash = base_build_handler.get_file_hash(deqp_deps)
+
+ return self._compare_build_hash(current_build_hash, base_build_hash)
+
+
+ def compare_base_build_with_device_files(self, deqp_deps, adb, base_build_file):
+ """Compare the difference of files on device and base build with dEQP dependency.
+
+ If the difference doesn't involve dEQP dependency, current build could skip dEQP test if
+ base build has passed test.
+
+ Args:
+ deqp_deps: a set of dEQP dependency.
+ adb: an instance of AdbHelper for current device under test.
+ base_build_file: base build file name.
+ Returns:
+ True if current build could skip dEQP, otherwise False.
+ Dictionary of changed dependencies and their details.
+ """
+ print('Comparing base build and current build on the device...')
+ # Get current build's hash.
+ current_build_hash = dict()
+ for dep in deqp_deps:
+ content = adb.run_shell_command('cat ' + dep)
+ current_build_hash[dep] = hash(content)
+
+ base_build_handler = self._build_file_handler(base_build_file)
+ base_build_hash = base_build_handler.get_file_hash(deqp_deps)
+
+ return self._compare_build_hash(current_build_hash, base_build_hash)
+
+ def get_system_fingerprint(self, build_file):
+ """Get build fingerprint in SYSTEM partition.
+
+ Returns:
+ String of build fingerprint.
+ """
+ return self._build_file_handler(build_file).get_system_fingerprint()
+
+
+ def _compare_build_hash(self, current_build_hash, base_build_hash):
+ """Compare the hash value of current build and base build.
+
+ Args:
+ current_build_hash: map of current build where key is file name, and value is content hash.
+ base_build_hash: map of base build where key is file name and value is content hash.
+ Returns:
+ Boolean about if two builds' hash is the same.
+ Dictionary of changed dependencies and their details.
+ """
+ changes = {}
+ if current_build_hash == base_build_hash:
+ print('Done!')
+ return True, changes
+
+ for key, val in current_build_hash.items():
+ if key not in base_build_hash:
+ detail = 'File:{build_file} was not found in base build'.format(build_file=key)
+ changes[key] = detail
+ logger.info(detail)
+ elif base_build_hash[key] != val:
+ detail = ('Detected dEQP dependency file difference:{deps}. Base build hash:{base}, '
+ 'current build hash:{current}'.format(deps=key, base=base_build_hash[key],
+ current=val))
+ changes[key] = detail
+ logger.info(detail)
+
+ print('Done!')
+ return False, changes
+
+
+class AdbHelper(object):
+ """Helper class for running adb."""
+
+ def __init__(self, device_serial=None):
+ """Initialize AdbHelper.
+
+ Args:
+ device_serial: A string of device serial number, optional.
+ """
+ self._device_serial = device_serial
+
+ def _run_adb_command(self, *args):
+ """Run adb command."""
+ adb_cmd = ['adb']
+ if self._device_serial:
+ adb_cmd.extend(['-s', self._device_serial])
+ adb_cmd.extend(args)
+ adb_cmd = ' '.join(adb_cmd)
+ completed = subprocess.run(adb_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+ if completed.returncode != 0:
+ raise AdbError('adb command: {cmd} failed with error: {error}'
+ .format(cmd=adb_cmd, error=completed.stderr))
+
+ return completed.stdout
+
+ def push_file(self, source_file, destination_file):
+ """Push a file from device to host.
+
+ Args:
+ source_file: A string representing file to push.
+ destination_file: A string representing target on device to push to.
+ """
+ return self._run_adb_command('push', source_file, destination_file)
+
+ def pull_file(self, source_file, destination_file):
+ """Pull a file to device.
+
+ Args:
+ source_file: A string representing file on device to pull.
+ destination_file: A string representing target on host to pull to.
+ """
+ return self._run_adb_command('pull', source_file, destination_file)
+
+ def get_fingerprint(self):
+ """Get fingerprint of the device."""
+ return self._run_adb_command('shell', 'getprop ro.build.fingerprint').decode("utf-8").strip()
+
+ def run_shell_command(self, command):
+ """Run a adb shell command.
+
+ Args:
+ command: A string of command to run, executed through 'adb shell'
+ """
+ return self._run_adb_command('shell', command)
+
+
+class DeqpDependencyCollector(object):
+ """Collect dEQP dependency from device under test."""
+
+ def __init__(self, work_dir, test_dir, adb):
+ """Init DeqpDependencyCollector.
+
+ Args:
+ work_dir: path of directory for saving script result and logs.
+ test_dir: path of directory for incremental dEQP test file.
+ adb: an instance of AdbHelper.
+ """
+ self._work_dir = work_dir
+ self._test_dir = test_dir
+ self._adb = adb
+ # dEQP dependency with pattern below are not an actual file:
+ # files has prefix /data/ are not system files, e.g. intermediate files.
+ # [vdso] is virtual dynamic shared object.
+ # /dmabuf is a temporary file.
+ self._exclude_deqp_pattern = re.compile('(^/data/|^\[vdso\]|^/dmabuf)')
+
+ def check_test_log(self, test_file, log_file):
+ """Check test's log to see if all tests are executed.
+
+ Args:
+ test_file: Name of test .txt file.
+ log_content: Name of log file.
+ Returns:
+ True if all tests are executed, otherwise False.
+ """
+ test_cnt = 0
+ with open(test_file, 'r') as f:
+ for _ in f:
+ test_cnt += 1
+
+ executed_test_cnt = 0
+
+ with open(log_file, 'r') as f:
+ for line in f:
+ # 'NotSupported' status means test is not supported in device.
+ # TODO(yichunli): Check with graphics team if failed test is allowed.
+ if ('StatusCode="Pass"' in line or 'StatusCode="NotSupported"' in line or
+ 'StatusCode="Fail"' in line):
+ executed_test_cnt += 1
+ return executed_test_cnt == test_cnt
+
+ def update_dependency(self, deps, dump):
+ """Parse perf dump file and update dEQP dependency.
+
+ Below is an example of how dump file looks like:
+ 630 record comm: type 3, misc 0, size 64
+ 631 pid 23365, tid 23365, comm simpleperf
+ 632 sample_id: pid 0, tid 0
+ 633 sample_id: time 0
+ 634 sample_id: id 23804
+ 635 sample_id: cpu 0, res 0
+ .......
+ 684 record comm: type 3, misc 8192, size 64
+ 685 pid 23365, tid 23365, comm deqp-binary64
+ 686 sample_id: pid 23365, tid 23365
+ 687 sample_id: time 595063921159958
+ 688 sample_id: id 23808
+ 689 sample_id: cpu 4, res 0
+ .......
+ 698 record mmap2: type 10, misc 8194, size 136
+ 699 pid 23365, tid 23365, addr 0x58b817b000, len 0x3228000
+ 700 pgoff 0x0, maj 253, min 9, ino 14709, ino_generation 2575019956
+ 701 prot 1, flags 6146, filename /data/local/tmp/deqp-binary64
+ 702 sample_id: pid 23365, tid 23365
+ 703 sample_id: time 595063921188552
+ 704 sample_id: id 23808
+ 705 sample_id: cpu 4, res 0
+
+ Args:
+ deps: a set of string containing dEQP dependency.
+ dump: perf dump file's name.
+ """
+ binary_executed = False
+ correct_mmap = False
+ with open(dump, 'r') as f:
+ for line in f:
+ # It means dEQP binary starts to be executed.
+ if re.search(' comm .*deqp-binary', line):
+ binary_executed = True
+ if not binary_executed:
+ continue
+ # We get a new perf event
+ if not line.startswith(' '):
+ # mmap with misc 1 is not for deqp binary.
+ correct_mmap = line.startswith('record mmap') and 'misc 1,' not in line
+ # Get file name in memory map.
+ if 'filename' in line and correct_mmap:
+ deps_file = line[line.find('filename') + 9:].strip()
+ if not re.search(self._exclude_deqp_pattern, deps_file):
+ deps.add(deps_file)
+
+
+ def get_test_binary_name(self, test_name):
+ """Get dEQP binary's name based on test name.
+
+ Args:
+ test_name: name of test.
+ Returns:
+ dEQP binary's name.
+ """
+ if test_name.endswith('32'):
+ return 'deqp-binary'
+ elif test_name.endswith('64'):
+ return 'deqp-binary64'
+ else:
+ raise TestError('Fail to get dEQP binary due to unknonw test name: ' + test_name)
+
+ def get_test_log_name(self, test_name):
+ """Get test log's name based on test name.
+
+ Args:
+ test_name: name of test.
+ Returns:
+ test log's name when running dEQP test.
+ """
+ return test_name + '.qpa'
+
+ def get_test_perf_name(self, test_name):
+ """Get perf file's name based on test name.
+
+ Args:
+ test_name: name of test.
+ Returns:
+ perf file's name.
+ """
+ return test_name + '.data'
+
+ def get_perf_dump_name(self, test_name):
+ """Get perf dump file's name based on test name.
+
+ Args:
+ test_name: name of test.
+ Returns:
+ perf dump file's name.
+ """
+ return test_name + '-perf-dump.txt'
+
+ def get_test_list_name(self, test_name):
+ """Get test list file's name based on test name.
+
+ test list file is used to run dEQP test.
+
+ Args:
+ test_name: name of test.
+ Returns:
+ test list file's name.
+ """
+ if test_name.startswith('vk'):
+ return 'vk-master-subset.txt'
+ elif test_name.startswith('gles3'):
+ return 'gles3-master-subset.txt'
+ else:
+ raise TestError('Fail to get test list due to unknown test name: ' + test_name)
+
+ def get_deqp_dependency(self):
+ """Get dEQP dependency.
+
+ Returns:
+ A set of dEQP dependency.
+ """
+ device_deqp_dir = '/data/local/tmp'
+ device_deqp_out_dir = '/data/local/tmp/out'
+ test_list = ['vk-32', 'vk-64', 'gles3-32', 'gles3-64']
+
+ # Clean up the device.
+ self._adb.run_shell_command('mkdir -p ' + device_deqp_out_dir)
+
+ # Copy test resources to device.
+ logger.info(self._adb.push_file(self._test_dir + '/*', device_deqp_dir))
+
+ # Run the dEQP binary with simpleperf
+ print('Running a subset of dEQP tests as binary on the device...')
+ deqp_deps = set()
+ for test in test_list:
+ test_file = os.path.join(device_deqp_dir, self.get_test_list_name(test))
+ log_file = os.path.join(device_deqp_out_dir, self.get_test_log_name(test))
+ perf_file = os.path.join(device_deqp_out_dir, self.get_test_perf_name(test))
+ deqp_binary = os.path.join(device_deqp_dir, self.get_test_binary_name(test))
+ simpleperf_command = ('"cd {device_deqp_dir} && simpleperf record -o {perf_file} {binary} '
+ '--deqp-caselist-file={test_list} --deqp-log-images=disable '
+ '--deqp-log-shader-sources=disable --deqp-log-filename={log_file} '
+ '--deqp-surface-type=fbo --deqp-surface-width=2048 '
+ '--deqp-surface-height=2048"')
+ self._adb.run_shell_command(
+ simpleperf_command.format(device_deqp_dir=device_deqp_dir, binary=deqp_binary,
+ perf_file=perf_file, test_list=test_file, log_file=log_file))
+
+ # Check test log.
+ host_log_file = os.path.join(self._work_dir, self.get_test_log_name(test))
+ self._adb.pull_file(log_file, host_log_file )
+ if not self.check_test_log(os.path.join(self._test_dir, self.get_test_list_name(test)),
+ host_log_file):
+ error_msg = ('Fail to run incremental dEQP because of crashed test. Check test'
+ 'log {} for more detail.').format(host_log_file)
+ logger.error(error_msg)
+ raise TestError(error_msg)
+ print('Tests are all passed!')
+
+ # Parse perf dump result to get dependency.
+ print('Analyzing dEQP dependency...')
+ for test in test_list:
+ perf_file = os.path.join(device_deqp_out_dir, self.get_test_perf_name(test))
+ dump_file = os.path.join(self._work_dir, self.get_perf_dump_name(test))
+ self._adb.run_shell_command('simpleperf dump {perf_file} > {dump_file}'
+ .format(perf_file=perf_file, dump_file=dump_file))
+ self.update_dependency(deqp_deps, dump_file)
+ print('Done!')
+ return deqp_deps
+
+def _is_deqp_dependency(dependency_name):
+ """Check if dependency is related to dEQP."""
+ # dEQP dependency with pattern below will not be used to compare build:
+ # files has /apex/ prefix are not related to dEQP.
+ return not re.search(re.compile('^/apex/'), dependency_name)
+
+def _get_parser():
+ parser = argparse.ArgumentParser(description='Run incremental dEQP on devices.')
+ parser.add_argument('-s', '--serial', help='Optional. Use device with given serial.')
+ parser.add_argument('-t', '--test', help=('Optional. Directory of incremental deqp test file. '
+ 'This directory should have test resources and dEQP '
+ 'binaries.'))
+ parser.add_argument('-b', '--base_build', help=('Target file of base build that has passed dEQP '
+ 'test, e.g. flame-target_files-6935423.zip.'))
+ parser.add_argument('-c', '--current_build',
+ help=('Optional. When empty, the script will read files in the build from '
+ 'the device via adb. When set, the script will read build files from '
+ 'the file provided by this argument. And this file should be the '
+ 'current build that is flashed to device, such as a target file '
+ 'like flame-target_files-6935424.zip. This argument can be used when '
+ 'some dependencies files are not accessible via adb.'))
+ parser.add_argument('--generate_deps_only', action='store_true',
+ help=('Run test and generate dEQP dependency list only '
+ 'without comparing build.'))
+ parser.add_argument('--ats_mode', action='store_true',
+ help=('Run incremental dEQP with Android Test Station.'))
+ parser.add_argument('--custom_handler', action='store_true',
+ help='Use custome build file handler')
+ return parser
+
+def _create_logger(log_file_name):
+ """Create logger.
+
+ Args:
+ log_file_name: absolute path of the log file.
+ Returns:
+ a logging.Logger
+ """
+ logging.basicConfig(filename=log_file_name)
+ logger = logging.getLogger()
+ logger.setLevel(level=logging.NOTSET)
+ return logger
+
+def _save_deqp_deps(deqp_deps, file_name):
+ """Save dEQP dependency to file.
+
+ Args:
+ deqp_deps: a set of dEQP dependency.
+ file_name: name of the file to save dEQP dependency.
+ Returns:
+ name of the file that saves dEQP dependency.
+ """
+ with open(file_name, 'w') as f:
+ for dep in sorted(deqp_deps):
+ f.write(dep+'\n')
+ return file_name
+
+def _generate_report(
+ report_name,
+ base_build_fingerprint,
+ current_build_fingerprint,
+ deqp_deps,
+ extra_deqp_deps,
+ deqp_deps_changes):
+ """Generate a json report.
+
+ Args:
+ report_name: absolute file name of report.
+ base_build_fingerprint: fingerprint of the base build.
+ current_build_fingerprint: fingerprint of the current build.
+ deqp_deps: list of dEQP dependencies generated by the tool.
+ extra_deqp_deps: list of extra dEQP dependencies.
+ deqp_deps_changes: dictionary of dependency changes.
+ """
+ data = {}
+ data['base_build_fingerprint'] = base_build_fingerprint
+ data['current_build_fingerprint'] = current_build_fingerprint
+ data['deqp_deps'] = sorted(list(deqp_deps))
+ data['extra_deqp_deps'] = sorted(list(extra_deqp_deps))
+ data['deqp_deps_changes'] = deqp_deps_changes
+
+ with open(report_name, 'w') as f:
+ json.dump(data, f, indent=4)
+
+ print('Incremental dEQP report is generated at: ' + report_name)
+
+
+def _local_run(args, work_dir):
+ """Run incremental dEQP locally.
+
+ Args:
+ args: return of parser.parse_args().
+ work_dir: path of directory for saving script result and logs.
+ """
+ print('Logs and simpleperf results will be copied to: ' + work_dir)
+ if args.test:
+ test_dir = args.test
+ else:
+ test_dir = os.path.dirname(os.path.abspath(__file__))
+ # Extra dEQP dependencies are the files can't be loaded to memory such as firmware.
+ extra_deqp_deps = set()
+ extra_deqp_deps_file = os.path.join(test_dir, 'extra_deqp_dependency.txt')
+ if not os.path.exists(extra_deqp_deps_file):
+ if not args.generate_deps_only:
+ raise TestResourceError('{test_resource} doesn\'t exist'
+ .format(test_resource=extra_deqp_deps_file))
+ else:
+ with open(extra_deqp_deps_file, 'r') as f:
+ for line in f:
+ extra_deqp_deps.add(line.strip())
+
+ if args.serial:
+ adb = AdbHelper(args.serial)
+ else:
+ adb = AdbHelper()
+
+ dependency_collector = DeqpDependencyCollector(work_dir, test_dir, adb)
+ deqp_deps = dependency_collector.get_deqp_dependency()
+ aggregated_deqp_deps = deqp_deps.union(extra_deqp_deps)
+
+ deqp_deps_file_name = _save_deqp_deps(aggregated_deqp_deps,
+ os.path.join(work_dir, 'dEQP-dependency.txt'))
+ print('dEQP dependency list has been generated in: ' + deqp_deps_file_name)
+
+ if args.generate_deps_only:
+ return
+
+ # Compare the build difference with dEQP dependency
+ valid_deqp_deps = [dep for dep in aggregated_deqp_deps if _is_deqp_dependency(dep)]
+ build_helper = BuildHelper(args.custom_handler)
+ if args.current_build:
+ skip_dEQP, changes = build_helper.compare_base_build_with_current_build(
+ valid_deqp_deps, args.current_build, args.base_build)
+ else:
+ skip_dEQP, changes = build_helper.compare_base_build_with_device_files(
+ valid_deqp_deps, adb, args.base_build)
+ if skip_dEQP:
+ print('Congratulations, current build could skip dEQP test.\n'
+ 'If you run CTS through suite, you could pass filter like '
+ '\'--exclude-filter CtsDeqpTestCases\'.')
+ else:
+ print('Sorry, current build can\'t skip dEQP test because dEQP dependency has been '
+ 'changed.\nPlease check logs for more details.')
+
+ _generate_report(os.path.join(work_dir, REPORT_FILENAME),
+ build_helper.get_system_fingerprint(args.base_build),
+ adb.get_fingerprint(),
+ deqp_deps,
+ extra_deqp_deps,
+ changes)
+
+def _generate_cts_xml(out_dir, content):
+ """Generate cts configuration for Android Test Station.
+
+ Args:
+ out_dir: output directory for cts confiugration.
+ content: configuration content.
+ """
+ with open(os.path.join(out_dir, 'incremental_deqp.xml'), 'w') as f:
+ f.write(content)
+
+
+def _ats_run(args, work_dir):
+ """Run incremental dEQP with Android Test Station.
+
+ Args:
+ args: return of parser.parse_args().
+ work_dir: path of directory for saving script result and logs.
+ """
+ # Extra dEQP dependencies are the files can't be loaded to memory such as firmware.
+ extra_deqp_deps = set()
+ with open(os.path.join(work_dir, 'extra_deqp_dependency.txt'), 'r') as f:
+ for line in f:
+ if line.strip():
+ extra_deqp_deps.add(line.strip())
+
+ android_serials = os.getenv('ANDROID_SERIALS')
+ if not android_serials:
+ raise AtsError('Fail to read environment variable ANDROID_SERIALS.')
+ first_device_serial = android_serials.split(',')[0]
+ adb = AdbHelper(first_device_serial)
+
+ dependency_collector = DeqpDependencyCollector(work_dir,
+ os.path.join(work_dir, 'test_resources'), adb)
+ deqp_deps = dependency_collector.get_deqp_dependency()
+ aggregated_deqp_deps = deqp_deps.union(extra_deqp_deps)
+
+ deqp_deps_file_name = _save_deqp_deps(aggregated_deqp_deps,
+ os.path.join(work_dir, 'dEQP-dependency.txt'))
+
+ if args.generate_deps_only:
+ _generate_cts_xml(work_dir, DEFAULT_CTS_XML)
+ return
+
+ # Compare the build difference with dEQP dependency
+ valid_deqp_deps = [dep for dep in aggregated_deqp_deps if _is_deqp_dependency(dep)]
+
+ # base build target file is from test resources.
+ base_build_target = os.path.join(work_dir, 'base_build_target_files')
+ build_helper = BuildHelper(args.custom_handler)
+ if args.current_build:
+ skip_dEQP, changes = build_helper.compare_base_build_with_current_build(
+ valid_deqp_deps, args.current_build, args.base_build)
+ else:
+ skip_dEQP, changes = build_helper.compare_base_build_with_device_files(
+ valid_deqp_deps, adb, args.base_build)
+ if skip_dEQP:
+ _generate_cts_xml(work_dir, INCREMENTAL_DEQP_XML)
+ else:
+ _generate_cts_xml(work_dir, DEFAULT_CTS_XML)
+
+ _generate_report(os.path.join(work_dir, REPORT_FILENAME),
+ build_helper.get_system_fingerprint(args.base_build),
+ adb.get_fingerprint(),
+ deqp_deps,
+ extra_deqp_deps,
+ changes)
+
+def main():
+ parser = _get_parser()
+ args = parser.parse_args()
+ if not args.generate_deps_only and not args.base_build and not args.ats_mode:
+ parser.error('Base build argument: \'-b [file] or --base_build [file]\' '
+ 'is required to compare build.')
+
+ work_dir = ''
+ log_file_name = ''
+ if args.ats_mode:
+ work_dir = os.getenv('TF_WORK_DIR')
+ log_file_name = os.path.join('/data/tmp', 'incremental-deqp-log-'+str(uuid.uuid4()))
+ else:
+ work_dir = tempfile.mkdtemp(prefix='incremental-deqp-'
+ + time.strftime("%Y%m%d-%H%M%S"))
+ log_file_name = os.path.join(work_dir, 'incremental-deqp-log')
+ global logger
+ logger = _create_logger(log_file_name)
+
+ if args.ats_mode:
+ _ats_run(args, work_dir)
+ else:
+ _local_run(args, work_dir)
+
+if __name__ == '__main__':
+ main()
+
diff --git a/tools/incremental-cts/incremental_deqp_test.py b/tools/incremental-cts/incremental_deqp_test.py
new file mode 100644
index 0000000..eedcc88
--- /dev/null
+++ b/tools/incremental-cts/incremental_deqp_test.py
@@ -0,0 +1,185 @@
+# Lint as: python3
+#
+# 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.
+
+"""Tests for incremental_deqp."""
+
+import incremental_deqp
+import os
+import unittest
+from unittest.mock import MagicMock
+from unittest.mock import patch
+
+@patch('incremental_deqp.AdbHelper', MagicMock())
+class IncrementalDeqpTest(unittest.TestCase):
+
+ def setUp(self):
+ testfile_dir = os.path.dirname(os.path.abspath(__file__))
+ self.testdata_dir = testfile_dir +'/testdata'
+ self.dependency_collector = incremental_deqp.DeqpDependencyCollector(None, None, None)
+ self.parser = incremental_deqp._get_parser()
+
+ def test_update_dependency(self):
+ """Test update_dependency gets correct dEQP dependency from dump file."""
+ dump_file = 'testdata/perf_dump.txt'
+ deps = set()
+ self.dependency_collector.update_dependency(deps, dump_file)
+ self.assertEqual(len(deps),2)
+ self.assertIn('file_2', deps)
+ self.assertIn('file_3', deps)
+
+ def test_check_test_log_all_test_executed(self):
+ """Test check_test_log returns true if all tests are executed."""
+ test_file = 'testdata/test_list.txt'
+ log_file = 'testdata/log_1.qpa'
+ self.assertTrue(self.dependency_collector.check_test_log(test_file, log_file))
+
+ def test_check_test_log_test_crashed(self):
+ """Test check_test_log returns false if tests are crashed."""
+ test_file = 'testdata/test_list.txt'
+ log_file = 'testdata/log_2.qpa'
+ self.assertFalse(self.dependency_collector.check_test_log(test_file, log_file))
+
+ def test_get_test_binary_name(self):
+ """Test get_test_binary_name gets dEQP binary name based on test name."""
+ self.assertEqual(self.dependency_collector.get_test_binary_name('vk-32'), 'deqp-binary')
+ self.assertEqual(self.dependency_collector.get_test_binary_name('vk-64'), 'deqp-binary64')
+ with self.assertRaises(incremental_deqp.TestError):
+ self.dependency_collector.get_test_binary_name('test')
+
+ def test_get_test_log_name(self):
+ """Test get_test_log_name gets correct test log name based on test name."""
+ self.assertEqual(self.dependency_collector.get_test_log_name('test'), 'test.qpa')
+
+ def test_get_perf_name(self):
+ """Test get_perf_name gets correct perf file name based on test name."""
+ self.assertEqual(self.dependency_collector.get_test_perf_name('test'), 'test.data')
+
+ def test_get_perf_dump_name(self):
+ """Test get_perf_dump_name gets correct perf dump file name based on test name."""
+ self.assertEqual(self.dependency_collector.get_perf_dump_name('test'), 'test-perf-dump.txt')
+
+ def test_get_test_list_name(self):
+ """Test get_test_list_name gets test list name based on test name."""
+ self.assertEqual(self.dependency_collector.get_test_list_name('vk-32'), 'vk-master-subset.txt')
+ self.assertEqual(self.dependency_collector.get_test_list_name('gles3-32'),
+ 'gles3-master-subset.txt')
+ with self.assertRaises(incremental_deqp.TestError):
+ self.dependency_collector.get_test_list_name('test')
+
+ def test_valid_dependency(self):
+ """Test if dependency is valid."""
+ self.assertTrue(incremental_deqp._is_deqp_dependency('/file/a.so'))
+ self.assertFalse(incremental_deqp._is_deqp_dependency('/apex/a.so'))
+
+ def test_build_helper_compare_build_with_device_files_true(self):
+ """Test BuildHelper.compare_base_build_with_device_files returns true."""
+ build_helper = incremental_deqp.BuildHelper()
+ deqp_deps = ['/system/deqp_dependency_file_a.so', '/vendor/deqp_dependency_file_b.so']
+ base_build_file = './testdata/base_build_target-files.zip'
+
+ def side_effect(command):
+ if 'file_a.so' in command:
+ return b'placeholder\nplaceholder\n'
+ if 'file_b.so' in command:
+ return b'placeholder\nplaceholder\nplaceholder\n\n'
+
+ adb = incremental_deqp.AdbHelper()
+ adb.run_shell_command = MagicMock(side_effect=side_effect)
+ self.assertTrue(build_helper.compare_base_build_with_device_files(
+ deqp_deps, adb, base_build_file)[0])
+
+ def test_compare_build_with_device_files_false(self):
+ """Test BuildHelper.compare_base_build_with_device_files returns false."""
+ deqp_deps = ['/system/deqp_dependency_file_a.so', '/vendor/deqp_dependency_file_b.so']
+ build_helper = incremental_deqp.BuildHelper()
+ base_build_file = './testdata/base_build_target-files.zip'
+ def side_effect(command):
+ if 'file_a.so' in command:
+ return b'different text'
+ if 'file_b.so' in command:
+ return b'placeholder\nplaceholder\nplaceholder\n\n'
+
+ adb = incremental_deqp.AdbHelper()
+ adb.run_shell_command = MagicMock(side_effect=side_effect)
+ self.assertFalse(build_helper.compare_base_build_with_device_files(
+ deqp_deps, adb, base_build_file)[0])
+
+ def test_build_helper_compare_build_with_current_build_true(self):
+ """Test BuildHelper.compare_base_build_with_current_build returns true."""
+ build_helper = incremental_deqp.BuildHelper()
+ deqp_deps = ['/system/deqp_dependency_file_a.so', '/vendor/deqp_dependency_file_b.so']
+ base_build_file = './testdata/base_build_target-files.zip'
+
+ self.assertTrue(build_helper.compare_base_build_with_current_build(
+ deqp_deps, base_build_file, base_build_file)[0])
+
+ def test_build_helper_compare_build_with_current_build_false(self):
+ """Test BuildHelper.compare_base_build_with_current_build returns false."""
+ build_helper = incremental_deqp.BuildHelper()
+ deqp_deps = ['/system/deqp_dependency_file_a.so', '/vendor/deqp_dependency_file_b.so']
+ base_build_file = './testdata/base_build_target-files.zip'
+ current_build_file = './testdata/current_build_target-files.zip'
+
+ self.assertFalse(build_helper.compare_base_build_with_current_build(
+ deqp_deps, current_build_file, base_build_file)[0])
+
+ def test_build_helper_get_system_fingerprint(self):
+ """Test BuildHelper gets system fingerprint."""
+ build_helper = incremental_deqp.BuildHelper()
+ build_file = './testdata/base_build_target-files.zip'
+
+ self.assertEqual(('generic/aosp_cf_x86_64_phone/vsoc_x86_64:S/AOSP.MASTER/7363308:'
+ 'userdebug/test-keys'), build_helper.get_system_fingerprint(build_file))
+
+
+ @patch('incremental_deqp.BuildHelper', autospec=True)
+ @patch('incremental_deqp._save_deqp_deps', autospec=True)
+ @patch('incremental_deqp.DeqpDependencyCollector', autospec=True)
+ @patch('incremental_deqp.AdbHelper', autospec=True)
+ def test_local_run_generate_deps_only(self, adb_helper_mock, dependency_collector_mock,
+ save_deps_mock, build_helper_mock):
+ """Test generate_deps_only option in local_run."""
+ dependency_collector_mock.return_value.get_deqp_dependency.return_value = {'a.so'}
+ args = self.parser.parse_args(['--generate_deps_only'])
+ incremental_deqp._local_run(args, '')
+ save_deps_mock.assert_called_once_with({'a.so'}, 'dEQP-dependency.txt')
+ build_helper_mock.assert_not_called()
+
+ def test_local_run_missing_extra_deps(self):
+ """Test local_run throws exception if extra_deqp_dependency.txt is missing."""
+ args = self.parser.parse_args(['-t ./testdata'])
+ with self.assertRaises(incremental_deqp.TestResourceError):
+ incremental_deqp._local_run(args, '')
+
+ @patch('incremental_deqp._generate_report', autospec=True)
+ @patch('incremental_deqp.BuildHelper', autospec=True)
+ @patch('incremental_deqp._save_deqp_deps', autospec=True)
+ @patch('incremental_deqp.DeqpDependencyCollector', autospec=True)
+ @patch('incremental_deqp.AdbHelper', autospec=True)
+ def test_local_run_compare_build(self, adb_helper_mock, dependency_collector_mock,
+ save_deps_mock, build_helper_mock, generate_report_mock):
+ """Test local_run could compare build based on dependency."""
+ dependency_collector_mock.return_value.get_deqp_dependency.return_value = {'a.so'}
+ build_helper_mock.return_value.compare_base_build_with_device_files.return_value = [False, {}]
+ args = self.parser.parse_args(['-b', 'base_build', '-t', self.testdata_dir])
+
+ incremental_deqp._local_run(args, '')
+
+ save_deps_mock.assert_called_once_with({'a.so', 'extra_a.so'}, 'dEQP-dependency.txt')
+ build_helper_mock.assert_called_once_with(False)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tools/incremental-cts/target_file_handler.py b/tools/incremental-cts/target_file_handler.py
new file mode 100644
index 0000000..69189e6
--- /dev/null
+++ b/tools/incremental-cts/target_file_handler.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""File handler that reads target files."""
+
+from abstract_build_file_handler import *
+from zipfile import ZipFile
+
+class TargetFileHandler(AbstractBuildFileHandler):
+ """Reads file's content from target files."""
+
+ def __init__(self, build_file):
+ super().__init__(build_file)
+
+ def get_file_hash(self, file_names, hash_func=None):
+ """See base class."""
+ hash_dict = dict()
+ with ZipFile(self.build_file) as zip_file:
+ for file_name in file_names:
+ # Convert top directory's name to upper case.
+ idx = file_name[1:].find('/')+1
+ real_file_name = file_name[1:idx].upper()+file_name[idx:]
+ if real_file_name not in zip_file.namelist():
+ continue
+ with zip_file.open(real_file_name) as f:
+ if hash_func:
+ hash_dict[file_name] = hash_func(f.read())
+ else:
+ hash_dict[file_name] = hash(f.read())
+ return hash_dict
+
+ def get_system_fingerprint(self):
+ """See base class."""
+ fingerprint = ''
+ with ZipFile(self.build_file) as zip_file:
+ with zip_file.open('SYSTEM/build.prop') as build_prop:
+ for line in build_prop:
+ line = line.decode('UTF-8')
+ if 'build.fingerprint' not in line:
+ continue
+ fingerprint = line.split('=')[1].strip()
+ break
+ return fingerprint
diff --git a/tools/incremental-cts/target_file_handler_test.py b/tools/incremental-cts/target_file_handler_test.py
new file mode 100644
index 0000000..e89a1ad
--- /dev/null
+++ b/tools/incremental-cts/target_file_handler_test.py
@@ -0,0 +1,54 @@
+# Lint as: python3
+#
+# 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.
+
+"""Tests for target_file_handler."""
+
+import unittest
+from target_file_handler import *
+
+class BuildFileHandlerTest(unittest.TestCase):
+
+ def test_get_hash(self):
+ """Test TargetFileHandler could get hash from target file."""
+ build_file = './testdata/base_build_target-files.zip'
+ handler = TargetFileHandler(build_file)
+ deqp_deps = ['/system/deqp_dependency_file_a.so', '/vendor/deqp_dependency_file_b.so',
+ '/vendor/file_not_exists.so']
+ hash_dict = handler.get_file_hash(deqp_deps)
+
+ self.assertEqual(hash_dict['/system/deqp_dependency_file_a.so'],
+ hash(b'placeholder\nplaceholder\n'))
+ self.assertEqual(hash_dict['/vendor/deqp_dependency_file_b.so'],
+ hash(b'placeholder\nplaceholder\nplaceholder\n\n'))
+ self.assertEqual(len(hash_dict), 2)
+
+ def test_get_system_fingerprint(self):
+ """Test TargetFileHandler could get SYSTEM fingerprint from target file."""
+ build_file = './testdata/base_build_target-files.zip'
+ handler = TargetFileHandler(build_file)
+ self.assertEqual(('generic/aosp_cf_x86_64_phone/vsoc_x86_64:S/AOSP.MASTER/7363308:'
+ 'userdebug/test-keys'), handler.get_system_fingerprint())
+
+ def test_get_system_fingerprint_without_buildprop(self):
+ """Test TargetFileHandler get fingerprint raises exception if build.prop doesn't exist."""
+ build_file = './testdata/current_build_target-files.zip'
+ handler = TargetFileHandler(build_file)
+ with self.assertRaises(KeyError):
+ handler.get_system_fingerprint()
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tools/incremental-cts/testdata/base_build_target-files.zip b/tools/incremental-cts/testdata/base_build_target-files.zip
new file mode 100644
index 0000000..077a3f1
--- /dev/null
+++ b/tools/incremental-cts/testdata/base_build_target-files.zip
Binary files differ
diff --git a/tools/incremental-cts/testdata/current_build_target-files.zip b/tools/incremental-cts/testdata/current_build_target-files.zip
new file mode 100644
index 0000000..1bea4d4
--- /dev/null
+++ b/tools/incremental-cts/testdata/current_build_target-files.zip
Binary files differ
diff --git a/tools/incremental-cts/testdata/extra_deqp_dependency.txt b/tools/incremental-cts/testdata/extra_deqp_dependency.txt
new file mode 100644
index 0000000..57ee1ea
--- /dev/null
+++ b/tools/incremental-cts/testdata/extra_deqp_dependency.txt
@@ -0,0 +1 @@
+extra_a.so
diff --git a/tools/incremental-cts/testdata/log_1.qpa b/tools/incremental-cts/testdata/log_1.qpa
new file mode 100644
index 0000000..c0767f2
--- /dev/null
+++ b/tools/incremental-cts/testdata/log_1.qpa
@@ -0,0 +1,43 @@
+#beginTestCaseResult dEQP-VK.info.build
+<?xml version="1.0" encoding="UTF-8"?>
+<TestCaseResult Version="0.3.4" CasePath="dEQP-VK.info.build" CaseType="SelfValidate">
+ <Text>DE_OS: DE_OS_ANDROID
+DE_CPU: DE_CPU_ARM
+DE_PTR_SIZE: 4
+DE_ENDIANNESS: DE_LITTLE_ENDIAN
+DE_COMPILER: DE_COMPILER_CLANG
+DE_DEBUG: false
+</Text>
+ <Number Name="TestDuration" Description="Test case duration in microseconds" Tag="Time" Unit="us">52</Number>
+ <Result StatusCode="Pass">Not validated</Result>
+</TestCaseResult>
+
+#endTestCaseResult
+
+#beginTestCaseResult dEQP-VK.info.device
+<?xml version="1.0" encoding="UTF-8"?>
+<TestCaseResult Version="0.3.4" CasePath="dEQP-VK.info.device" CaseType="SelfValidate">
+ <Text>Using --deqp-vk-device-id=1</Text>
+ <Text>apiVersion: 1.1.128
+driverVersion: 0x801ea000
+deviceName: Adreno (TM) 640
+vendorID: 0x00005143
+deviceID: 0x06040001
+</Text>
+ <Number Name="TestDuration" Description="Test case duration in microseconds" Tag="Time" Unit="us">24</Number>
+ <Result StatusCode="Fail">Not validated</Result>
+</TestCaseResult>
+
+#endTestCaseResult
+
+#beginTestCaseResult dEQP-VK.info.platform
+<?xml version="1.0" encoding="UTF-8"?>
+<TestCaseResult Version="0.3.4" CasePath="dEQP-VK.info.platform" CaseType="SelfValidate">
+ <Text>OS: Linux 4.14.180-g051355490483-ab6669324 #1 SMP PREEMPT Fri Jul 10 09:40:47 UTC 2020
+CPU: armv8l
+</Text>
+ <Number Name="TestDuration" Description="Test case duration in microseconds" Tag="Time" Unit="us">16</Number>
+ <Result StatusCode="NotSupported">Not validated</Result>
+</TestCaseResult>
+
+#endTestCaseResult
diff --git a/tools/incremental-cts/testdata/log_2.qpa b/tools/incremental-cts/testdata/log_2.qpa
new file mode 100644
index 0000000..98c9946
--- /dev/null
+++ b/tools/incremental-cts/testdata/log_2.qpa
@@ -0,0 +1,31 @@
+#beginTestCaseResult dEQP-VK.info.build
+<?xml version="1.0" encoding="UTF-8"?>
+<TestCaseResult Version="0.3.4" CasePath="dEQP-VK.info.build" CaseType="SelfValidate">
+ <Text>DE_OS: DE_OS_ANDROID
+DE_CPU: DE_CPU_ARM
+DE_PTR_SIZE: 4
+DE_ENDIANNESS: DE_LITTLE_ENDIAN
+DE_COMPILER: DE_COMPILER_CLANG
+DE_DEBUG: false
+</Text>
+ <Number Name="TestDuration" Description="Test case duration in microseconds" Tag="Time" Unit="us">52</Number>
+ <Result StatusCode="Pass">Not validated</Result>
+</TestCaseResult>
+
+#endTestCaseResult
+
+#beginTestCaseResult dEQP-VK.info.device
+<?xml version="1.0" encoding="UTF-8"?>
+<TestCaseResult Version="0.3.4" CasePath="dEQP-VK.info.device" CaseType="SelfValidate">
+ <Text>Using --deqp-vk-device-id=1</Text>
+ <Text>apiVersion: 1.1.128
+driverVersion: 0x801ea000
+deviceName: Adreno (TM) 640
+vendorID: 0x00005143
+deviceID: 0x06040001
+</Text>
+ <Number Name="TestDuration" Description="Test case duration in microseconds" Tag="Time" Unit="us">24</Number>
+ <Result StatusCode="Pass">Not validated</Result>
+</TestCaseResult>
+
+#endTestCaseResult
diff --git a/tools/incremental-cts/testdata/perf_dump.txt b/tools/incremental-cts/testdata/perf_dump.txt
new file mode 100644
index 0000000..1acd1b6
--- /dev/null
+++ b/tools/incremental-cts/testdata/perf_dump.txt
@@ -0,0 +1,68 @@
+record mmap2: type 10, misc 1, size 136
+ pid 23365, tid 23365, addr 0x58b817b000, len 0x3228000
+ pgoff 0x0, maj 253, min 9, ino 14709, ino_generation 2575019956
+ prot 1, flags 6146, filename file_0
+ sample_id: pid 23365, tid 23365
+ sample_id: time 595063921188552
+ sample_id: id 23808
+ sample_id: cpu 4, res 0
+record mmap2: type 10, misc 8194, size 136
+ pid 23365, tid 23365, addr 0x58b817b000, len 0x3228000
+ pgoff 0x0, maj 253, min 9, ino 14709, ino_generation 2575019956
+ prot 1, flags 6146, filename file_1
+ sample_id: pid 23365, tid 23365
+ sample_id: time 595063921188552
+ sample_id: id 23808
+ sample_id: cpu 4, res 0
+record comm: type 3, misc 0, size 64
+ pid 23365, tid 23365, comm simpleperf
+ sample_id: pid 0, tid 0
+ sample_id: time 0
+ sample_id: id 23804
+ sample_id: cpu 0, res 0
+record comm: type 3, misc 8192, size 64
+ pid 23365, tid 23365, comm deqp-binary64
+ sample_id: pid 23365, tid 23365
+ sample_id: time 595063921159958
+ sample_id: id 23808
+ sample_id: cpu 4, res 0
+record mmap2: type 10, misc 8194, size 136
+ pid 23365, tid 23365, addr 0x58b817b000, len 0x3228000
+ pgoff 0x0, maj 253, min 9, ino 14709, ino_generation 2575019956
+ prot 1, flags 6146, filename file_2
+ sample_id: pid 23365, tid 23365
+ sample_id: time 595063921188552
+ sample_id: id 23808
+ sample_id: cpu 4, res 0
+record mmap2: type 10, misc 8194, size 136
+ pid 23365, tid 23365, addr 0x58b817b000, len 0x3228000
+ pgoff 0x0, maj 253, min 9, ino 14709, ino_generation 2575019956
+ prot 1, flags 6146, filename /data/file
+ sample_id: pid 23365, tid 23365
+ sample_id: time 595063921188552
+ sample_id: id 23808
+ sample_id: cpu 4, res 0
+record mmap2: type 10, misc 8194, size 136
+ pid 23365, tid 23365, addr 0x58b817b000, len 0x3228000
+ pgoff 0x0, maj 253, min 9, ino 14709, ino_generation 2575019956
+ prot 1, flags 6146, filename /dmabuf:dmabuf1234
+ sample_id: pid 23365, tid 23365
+ sample_id: time 595063921188552
+ sample_id: id 23808
+ sample_id: cpu 4, res 0
+record mmap2: type 10, misc 8194, size 136
+ pid 23365, tid 23365, addr 0x58b817b000, len 0x3228000
+ pgoff 0x0, maj 253, min 9, ino 14709, ino_generation 2575019956
+ prot 1, flags 6146, filename [vdso]
+ sample_id: pid 23365, tid 23365
+ sample_id: time 595063921188552
+ sample_id: id 23808
+ sample_id: cpu 4, res 0
+record mmap2: type 10, misc 8194, size 136
+ pid 23365, tid 23365, addr 0x58b817b000, len 0x3228000
+ pgoff 0x0, maj 253, min 9, ino 14709, ino_generation 2575019956
+ prot 1, flags 6146, filename file_3
+ sample_id: pid 23365, tid 23365
+ sample_id: time 595063921188552
+ sample_id: id 23808
+ sample_id: cpu 4, res 0
diff --git a/tools/incremental-cts/testdata/test_list.txt b/tools/incremental-cts/testdata/test_list.txt
new file mode 100644
index 0000000..4811273
--- /dev/null
+++ b/tools/incremental-cts/testdata/test_list.txt
@@ -0,0 +1,3 @@
+dEQP-GLES3.info.vendor
+dEQP-GLES3.info.renderer
+dEQP-GLES3.info.version
diff --git a/tools/selinux/SELinuxNeverallowTestFrame.py b/tools/selinux/SELinuxNeverallowTestFrame.py
index 740e983..370b40b 100644
--- a/tools/selinux/SELinuxNeverallowTestFrame.py
+++ b/tools/selinux/SELinuxNeverallowTestFrame.py
@@ -36,13 +36,13 @@
* Neverallow Rules SELinux tests.
*/
public class SELinuxNeverallowRulesTest extends DeviceTestCase implements IBuildReceiver, IDeviceTest {
- private static final int Q_SEPOLICY_VERSION = 29;
private File sepolicyAnalyze;
private File devicePolicyFile;
private File deviceSystemPolicyFile;
private IBuildInfo mBuild;
private int mVendorSepolicyVersion = -1;
+ private int mSystemSepolicyVersion = -1;
/**
* A reference to the device under test.
@@ -83,6 +83,10 @@
mVendorSepolicyVersion =
android.security.cts.SELinuxHostTest.getVendorSepolicyVersion(mBuild, mDevice);
}
+ if (mSystemSepolicyVersion == -1) {
+ mSystemSepolicyVersion =
+ android.security.cts.SELinuxHostTest.getSystemSepolicyVersion(mBuild);
+ }
}
}
@@ -140,7 +144,7 @@
// If sepolicy is split and vendor sepolicy version is behind platform's,
// only test against platform policy.
File policyFile =
- (isSepolicySplit() && mVendorSepolicyVersion < Q_SEPOLICY_VERSION) ?
+ (isSepolicySplit() && mVendorSepolicyVersion < mSystemSepolicyVersion) ?
deviceSystemPolicyFile :
devicePolicyFile;
diff --git a/tools/utils/java-cert-list-generator.sh b/tools/utils/java-cert-list-generator.sh
index 1f33c4a..b69bec6 100755
--- a/tools/utils/java-cert-list-generator.sh
+++ b/tools/utils/java-cert-list-generator.sh
@@ -40,14 +40,12 @@
*/
package android.security.cts;
-import android.platform.test.annotations.SecurityTest;
/**
* Run "./cts/tools/utils/java-cert-list-generator.sh >
* cts/tests/tests/security/src/android/security/cts/CertificateData.java"
* to generate this file.
*/
-@SecurityTest
class CertificateData {
static final String[] CERTIFICATE_DATA = {
STARTCLASS
diff --git a/tools/vm-tests-tf/targetprep/Android.bp b/tools/vm-tests-tf/targetprep/Android.bp
new file mode 100644
index 0000000..76cb248
--- /dev/null
+++ b/tools/vm-tests-tf/targetprep/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_test_host {
+ name: "compatibility-host-vm-targetprep",
+ srcs: ["src/**/*.java"],
+ libs: [
+ "compatibility-host-util",
+ "cts-tradefed",
+ "tradefed",
+ ],
+
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+}
diff --git a/tools/vm-tests-tf/targetprep/Android.mk b/tools/vm-tests-tf/targetprep/Android.mk
deleted file mode 100644
index 8de699b..0000000
--- a/tools/vm-tests-tf/targetprep/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := compatibility-host-vm-targetprep
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts general-tests
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))