diff options
53 files changed, 865 insertions, 368 deletions
diff --git a/PermissionController/res/values-ar/strings.xml b/PermissionController/res/values-ar/strings.xml index 5381d11b4..e22ec0182 100644 --- a/PermissionController/res/values-ar/strings.xml +++ b/PermissionController/res/values-ar/strings.xml @@ -475,7 +475,7 @@ <string name="permgrouprequest_device_aware_storage_isolated" msgid="6463062962458809752">"هل تريد السماح لـ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بالوصول إلى الصور والوسائط على <b><xliff:g id="DEVICE_NAME">%2$s</xliff:g></b>؟"</string> <string name="permgrouprequest_contacts" msgid="8391550064551053695">"هل تريد السماح لتطبيق <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بالوصول إلى جهات الاتصال؟"</string> <string name="permgrouprequest_device_aware_contacts" msgid="731025863972535928">"هل تريد السماح لـ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بالوصول إلى جهات اتصالك على <b><xliff:g id="DEVICE_NAME">%2$s</xliff:g></b>؟"</string> - <string name="permgrouprequest_location" msgid="6990232580121067883">"هل تريد السماح لتطبيق <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بالوصول إلى الموقع الجغرافي لهذا الجهاز؟"</string> + <string name="permgrouprequest_location" msgid="6990232580121067883">"هل مطلوب السماح لتطبيق <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بالوصول إلى الموقع الجغرافي لهذا الجهاز؟"</string> <string name="permgrouprequest_device_aware_location" msgid="6075412127429878638">"هل تريد السماح لـ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بالوصول إلى الموقع الجغرافي الخاص بـ <b><xliff:g id="DEVICE_NAME">%2$s</xliff:g></b>؟"</string> <string name="permgrouprequestdetail_location" msgid="2635935335778429894">"لن يكون بإمكان التطبيق الوصول إلى الموقع الجغرافي إلا عند استخدامك لهذا التطبيق."</string> <string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"هل تريد السماح لتطبيق <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بالوصول إلى الموقع الجغرافي لهذا الجهاز؟"</string> @@ -495,7 +495,7 @@ <string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"تقريبي"</string> <string name="permgrouprequest_calendar" msgid="1493150855673603806">"هل تريد السماح لتطبيق <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بالوصول إلى التقويم؟"</string> <string name="permgrouprequest_device_aware_calendar" msgid="7161929851377463612">"هل تريد السماح لـ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بالوصول إلى تقويمك على <b><xliff:g id="DEVICE_NAME">%2$s</xliff:g></b>؟"</string> - <string name="permgrouprequest_sms" msgid="5672063688745420991">"هل تريد السماح لتطبيق <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بإرسال رسائل SMS وعرضها؟"</string> + <string name="permgrouprequest_sms" msgid="5672063688745420991">"هل مطلوب السماح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> بإرسال رسائل SMS وعرضها؟"</string> <string name="permgrouprequest_device_aware_sms" msgid="6639977653040502291">"هل تريد السماح لـ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بإرسال الرسائل القصيرة وعرضها على <b><xliff:g id="DEVICE_NAME">%2$s</xliff:g></b>؟"</string> <string name="permgrouprequest_storage" msgid="8717773092518621602">"هل تريد السماح لتطبيق <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بالوصول إلى الصور والوسائط والملفات على جهازك؟"</string> <string name="permgrouprequest_device_aware_storage" msgid="6933251810928606636">"هل تريد السماح لـ <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بالوصول إلى الصور والوسائط والملفات على <b><xliff:g id="DEVICE_NAME">%2$s</xliff:g></b>؟"</string> diff --git a/PermissionController/res/values-cs/strings.xml b/PermissionController/res/values-cs/strings.xml index 8ca485fbe..a48d5afb9 100644 --- a/PermissionController/res/values-cs/strings.xml +++ b/PermissionController/res/values-cs/strings.xml @@ -383,7 +383,7 @@ <string name="role_emergency_search_keywords" msgid="1920007722599213358">"v případě nouze"</string> <string name="role_home_label" msgid="3871847846649769412">"Výchozí aplikace pro domácnost"</string> <string name="role_home_short_label" msgid="8544733747952272337">"Vstupní aplikace"</string> - <string name="role_home_description" msgid="7997371519626556675">"Aplikace (tzv. spouštěče), které nahrazují plochu na zařízení Android a dávají vám přístup\\nk obsahu a funkcím zařízení."</string> + <string name="role_home_description" msgid="7997371519626556675">"Aplikace (tzv. spouštěče), které nahrazují plochu na zařízení Android a dávají vám přístup k obsahu a funkcím zařízení."</string> <string name="role_home_request_title" msgid="738136983453341081">"Nastavit <xliff:g id="APP_NAME">%1$s</xliff:g> jako výchozí aplikaci pro domácnost?"</string> <string name="role_home_request_description" msgid="2658833966716057673">"Není potřeba žádné oprávnění"</string> <string name="role_home_search_keywords" msgid="3830755001192666285">"spouštěč"</string> diff --git a/PermissionController/res/values-hu/strings.xml b/PermissionController/res/values-hu/strings.xml index 997dc71e2..038f0161f 100644 --- a/PermissionController/res/values-hu/strings.xml +++ b/PermissionController/res/values-hu/strings.xml @@ -495,7 +495,7 @@ <string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"Hozzávetőleges"</string> <string name="permgrouprequest_calendar" msgid="1493150855673603806">"Engedélyezi a(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> számára, hogy hozzáférjen a naptárhoz?"</string> <string name="permgrouprequest_device_aware_calendar" msgid="7161929851377463612">"Engedélyezi a(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> számára, hogy hozzáférjen a naptárához ezen az eszközön: <b><xliff:g id="DEVICE_NAME">%2$s</xliff:g>’s</b>?"</string> - <string name="permgrouprequest_sms" msgid="5672063688745420991">"Engedélyezi a(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> számára, hogy SMS-eket küldhessen és tekinthessen meg?"</string> + <string name="permgrouprequest_sms" msgid="5672063688745420991">"Engedélyezi a(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> számára SMS-ek küldését és megtekintését?"</string> <string name="permgrouprequest_device_aware_sms" msgid="6639977653040502291">"Engedélyezi a(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> számára az SMS-ek küldését és megtekintését ezen az eszközön: <b><xliff:g id="DEVICE_NAME">%2$s</xliff:g></b>?"</string> <string name="permgrouprequest_storage" msgid="8717773092518621602">"Engedélyezi a(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> számára, hogy hozzáférjen az eszközön tárolt fotókhoz, médiatartalmakhoz és fájlokhoz?"</string> <string name="permgrouprequest_device_aware_storage" msgid="6933251810928606636">"Engedélyezi a(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> számára, hogy fotókhoz, médiatartalmakhoz és fájlokhoz férjen hozzá ezen az eszközön: <b><xliff:g id="DEVICE_NAME">%2$s</xliff:g></b>?"</string> diff --git a/PermissionController/res/values-ja/strings.xml b/PermissionController/res/values-ja/strings.xml index 43e204b69..0be93d464 100644 --- a/PermissionController/res/values-ja/strings.xml +++ b/PermissionController/res/values-ja/strings.xml @@ -491,8 +491,8 @@ <string name="permgrouprequest_device_aware_fineupgrade" msgid="4453775952305587571">"<b><xliff:g id="DEVICE_NAME">%2$s</xliff:g></b>の位置情報に対する <b><xliff:g id="APP_NAME"><b>%1$s</b></xliff:g></b> のアクセス権を「おおよそ」から「正確」に変更しますか?"</string> <string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"このデバイスのおおよその位置情報へのアクセスを <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> に許可しますか?"</string> <string name="permgrouprequest_device_aware_coarselocation" msgid="8367540370912066757">"<b><xliff:g id="DEVICE_NAME">%2$s</xliff:g></b>のおおよその位置情報へのアクセスを <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> に許可しますか?"</string> - <string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"正確"</string> - <string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"おおよそ"</string> + <string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"正確な位置"</string> + <string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"おおよその位置"</string> <string name="permgrouprequest_calendar" msgid="1493150855673603806">"カレンダーへのアクセスを「<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>」に許可しますか?"</string> <string name="permgrouprequest_device_aware_calendar" msgid="7161929851377463612">"<b><xliff:g id="DEVICE_NAME">%2$s</xliff:g></b>内のカレンダーへのアクセスを <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> に許可しますか?"</string> <string name="permgrouprequest_sms" msgid="5672063688745420991">"SMS メッセージの送信と表示を「<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>」に許可しますか?"</string> diff --git a/PermissionController/res/values-mk/strings.xml b/PermissionController/res/values-mk/strings.xml index 5f2735642..d8ba89c77 100644 --- a/PermissionController/res/values-mk/strings.xml +++ b/PermissionController/res/values-mk/strings.xml @@ -628,7 +628,7 @@ <string name="safety_center_background_location_access_reminder_summary" msgid="7431657777510537658">"Апликацијава може секогаш да пристапува до вашата локација, дури и кога е затворена.\n\nНа одредени апликации за безбедност и итни случаи им е потребен пристап до вашата локација во заднината за правилно да функционираат."</string> <string name="safety_center_background_location_access_revoked" msgid="6972274943343442213">"Пристапот е променет"</string> <string name="safety_center_view_recent_location_access" msgid="3524391299490678243">"Погледнете го неодамнешното користење на локацијата"</string> - <string name="privacy_controls_title" msgid="7605929972256835199">"Контроли на приватноста"</string> + <string name="privacy_controls_title" msgid="7605929972256835199">"Контроли за приватност"</string> <string name="camera_toggle_title" msgid="1251201397431837666">"Пристап до камерата"</string> <string name="mic_toggle_title" msgid="2649991093496110162">"Пристап до микрофонот"</string> <string name="perm_toggle_description" msgid="7801326363741451379">"За апликации и услуги"</string> diff --git a/PermissionController/res/values-nb/strings.xml b/PermissionController/res/values-nb/strings.xml index e2930ac8a..3835d7573 100644 --- a/PermissionController/res/values-nb/strings.xml +++ b/PermissionController/res/values-nb/strings.xml @@ -443,7 +443,7 @@ <string name="default_app_recommended" msgid="5669584821778942909">"Optimalisert for enheten"</string> <string name="default_app_others" msgid="7793029848126079876">"Andre"</string> <string name="default_app_none" msgid="9084592086808194457">"Ingen"</string> - <string name="default_app_system_default" msgid="6218386768175513760">"(System-&shy;standard)"</string> + <string name="default_app_system_default" msgid="6218386768175513760">"(System-&#173;standard)"</string> <string name="default_app_no_apps" msgid="115720991680586885">"Ingen apper"</string> <string name="default_payment_app_other_nfc_services" msgid="5957633798695758917">"Andre NFC-tjenester"</string> <string name="car_default_app_selected" msgid="5416420830430644174">"Valgt"</string> diff --git a/PermissionController/res/values-pl/strings.xml b/PermissionController/res/values-pl/strings.xml index 8316ac98c..0aefe4a69 100644 --- a/PermissionController/res/values-pl/strings.xml +++ b/PermissionController/res/values-pl/strings.xml @@ -348,7 +348,7 @@ <string name="no_apps_allowed" msgid="7718822655254468631">"Nie zezwolono żadnym aplikacjom"</string> <string name="no_apps_allowed_full" msgid="8011716991498934104">"Brak aplikacji z uprawnieniami dla wszystkich plików"</string> <string name="no_apps_allowed_scoped" msgid="4908850477787659501">"Brak aplikacji z uprawnieniami tylko dla multimediów"</string> - <string name="no_apps_denied" msgid="7663435886986784743">"Nie zabroniono dostępu żadnym aplikacjom"</string> + <string name="no_apps_denied" msgid="7663435886986784743">"Nie odmówiono dostępu żadnym aplikacjom"</string> <string name="car_permission_selected" msgid="180837028920791596">"Wybrana"</string> <string name="settings" msgid="5409109923158713323">"Ustawienia"</string> <string name="accessibility_service_dialog_title_single" msgid="7956432823014102366">"Usługa <xliff:g id="SERVICE_NAME">%s</xliff:g> ma pełny dostęp do urządzenia"</string> diff --git a/PermissionController/res/values-ru-v33/strings.xml b/PermissionController/res/values-ru-v33/strings.xml index b45662712..5506ccd97 100644 --- a/PermissionController/res/values-ru-v33/strings.xml +++ b/PermissionController/res/values-ru-v33/strings.xml @@ -41,7 +41,7 @@ <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Переключатель: <xliff:g id="PRIVACY_CONTROL_TITLE">%1$s</xliff:g> (<xliff:g id="PRIVACY_CONTROL_STATUS">%2$s</xliff:g>)"</string> <string name="safety_center_qs_toggle_action" msgid="5920465736488119255">"Переключатель"</string> <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Открыть"</string> - <string name="safety_center_review_settings_button" msgid="938981137942443930">"Перейти в настройки"</string> + <string name="safety_center_review_settings_button" msgid="938981137942443930">"Открыть настройки"</string> <string name="safety_center_gear_label" msgid="5175877094379694098">"Настройки"</string> <string name="safety_center_info_label" msgid="8993181584061825412">"Информация"</string> </resources> diff --git a/PermissionController/res/values/strings.xml b/PermissionController/res/values/strings.xml index 5714a2460..f5a997674 100644 --- a/PermissionController/res/values/strings.xml +++ b/PermissionController/res/values/strings.xml @@ -1409,9 +1409,7 @@ <!-- Content for dialog shown when the user should confirm an incident / bug report. [CHAR LIMIT=none] --> - <string name="incident_report_dialog_text">"<xliff:g id="app_name" example="Gmail">%1$s</xliff:g> is requesting to upload a bug report from this device taken on <xliff:g id="date" example="December 26, 2018">%2$s</xliff:g> at <xliff:g id="time" example="1:20 PM">%3$s</xliff:g>. Bug reports include personal information about your device or logged by apps, for example, user names, location data, device identifiers, and network information. Only share bug reports with people and apps you trust with this information. - -Allow <xliff:g id="app_name" example="Gmail">%4$s</xliff:g> to upload a bug report?"</string> + <string name="incident_report_dialog_text">"<xliff:g id="app_name" example="Gmail">%1$s</xliff:g> is requesting to upload a bug report from this device taken on <xliff:g id="date" example="December 26, 2018">%2$s</xliff:g> at <xliff:g id="time" example="1:20 PM">%3$s</xliff:g>. Bug reports include personal information about your device or logged by apps, for example, user names, location data, device identifiers, and network information. Only share bug reports with people and apps you trust with this information.\n\nAllow <xliff:g id="app_name" example="Gmail">%4$s</xliff:g> to upload a bug report?"</string> <!-- Content for dialog shown when there was an error parsing the incident / bug report. [CHAR LIMIT=none] --> @@ -2031,17 +2029,15 @@ Allow <xliff:g id="app_name" example="Gmail">%4$s</xliff:g> to upload a bug repo <!--Title for dialog displayed to tell user that settings are blocked due to the phone state (such as being in a call with an unknown number) [CHAR LIMIT=50] --> <string name="enhanced_confirmation_phone_state_dialog_title">Can\u2019t complete action during call</string> <!--Content for dialog displayed to tell user that settings are blocked due to the phone state (such as being in a call with an unknown number) [CHAR LIMIT=NONE] --> - <string name="enhanced_confirmation_phone_state_dialog_desc"><xliff:g id="setting_description" example="allowing apps to install other apps">%1$s</xliff:g>\n\n - This setting is blocked to protect your device and data</string> + <string name="enhanced_confirmation_phone_state_dialog_desc">This setting is blocked to protect your device and data.<xliff:g id="scam_use_setting_description" example="scammers may ask you to allow apps to install other apps">%1$s</xliff:g></string> <!--Content explaining that the "install other apps" setting is blocked due to the phone state in a dialog displayed to the user [CHAR LIMIT=NONE] --> - <string name="enhanced_confirmation_phone_state_dialog_install_desc_prefix">Scammers may try to install harmful apps by asking you to install unknown apps from a new source.</string> + <string name="enhanced_confirmation_phone_state_dialog_install_desc"><xliff:g id="empty_line">\n\n</xliff:g>Scammers may try to install harmful apps by asking you to install unknown apps from a new source.</string> <!--Content explaining that the "enable accessibility service" setting is blocked due to the phone state in a dialog displayed to the user [CHAR LIMIT=NONE] --> - <string name="enhanced_confirmation_phone_state_dialog_a11y_desc_prefix">Scammers may try to take control of your device by asking you to allow accessibility access for an app.</string> - - <!--Content explaining that a generic setting is blocked due to the phone state in a dialog displayed to the user [CHAR LIMIT=NONE] --> - <string name="enhanced_confirmation_phone_state_dialog_generic_desc_prefix">Scammers may attempt to harm your device with this setting.</string> + <string name="enhanced_confirmation_phone_state_dialog_a11y_desc"><xliff:g id="empty_line">\n\n</xliff:g>Scammers may try to take control of your device by asking you to allow accessibility access for an app.</string> + <!--Content explaining that a generic setting is blocked due to the phone state in a dialog displayed to the user. currently empty [CHAR LIMIT=NONE] --> + <string name="enhanced_confirmation_phone_state_dialog_generic_desc" /> <!--Title for dialog displayed to tell user that permissions are blocked by setting restrictions [CHAR LIMIT=50] --> <string name="enhanced_confirmation_dialog_title_permission">App was denied access to <xliff:g id="permission_name" example="contacts">%1$s</xliff:g></string> diff --git a/PermissionController/res/xml/roles.xml b/PermissionController/res/xml/roles.xml index 0f9ff7112..4ba524462 100644 --- a/PermissionController/res/xml/roles.xml +++ b/PermissionController/res/xml/roles.xml @@ -902,6 +902,8 @@ <permission name="android.permission.READ_SMS" minSdkVersion="33" /> <permission name="android.permission.READ_PEOPLE_DATA" /> <permission name="android.permission.READ_GLOBAL_APP_SEARCH_DATA" /> + <permission name="android.permission.READ_BLOCKED_NUMBERS" + featureFlag="android.permission.flags.Flags.grantReadBlockedNumbersToSystemUiIntelligence" /> </permissions> </role> diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/Role.java b/PermissionController/role-controller/java/com/android/role/controller/model/Role.java index 1b7617b0d..0f79b19c0 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/model/Role.java +++ b/PermissionController/role-controller/java/com/android/role/controller/model/Role.java @@ -26,7 +26,6 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.SharedLibraryInfo; -import android.content.pm.Signature; import android.content.res.Resources; import android.os.Build; import android.os.UserHandle; @@ -505,8 +504,14 @@ public class Role { && Build.VERSION.SDK_INT <= mMaxSdkVersion; } - public boolean isStatic() { - return mStatic; + /** + * Check whether this role is static, which may change due to bypassing qualification. + * + * @param context the {@code Context} to retrieve system services + * @return whether this role is static + */ + public boolean isStatic(@NonNull Context context) { + return mStatic && !isBypassingQualification(context); } /** @@ -621,6 +626,12 @@ public class Role { return mAllowBypassingQualification; } + private boolean isBypassingQualification(@NonNull Context context) { + RoleManager roleManager = context.getSystemService(RoleManager.class); + return shouldAllowBypassingQualification(context) + && RoleManagerCompat.isBypassingRoleQualification(roleManager); + } + /** * Check whether a package is qualified for this role, i.e. whether it contains all the required * components (plus meeting some other general restrictions). @@ -633,9 +644,7 @@ public class Role { */ public boolean isPackageQualifiedAsUser(@NonNull String packageName, @NonNull UserHandle user, @NonNull Context context) { - RoleManager roleManager = context.getSystemService(RoleManager.class); - if (shouldAllowBypassingQualification(context) - && RoleManagerCompat.isBypassingRoleQualification(roleManager)) { + if (isBypassingQualification(context)) { return true; } @@ -983,7 +992,14 @@ public class Role { */ public void onHolderAddedAsUser(@NonNull String packageName, @NonNull UserHandle user, @NonNull Context context) { - RoleManagerCompat.setRoleFallbackEnabledAsUser(this, true, user, context); + if (RoleFlags.isProfileGroupExclusivityAvailable() + && com.android.permission.flags.Flags.crossUserRoleUxBugfixEnabled() + && getExclusivity() == Role.EXCLUSIVITY_PROFILE_GROUP) { + UserHandle profileParent = UserUtils.getProfileParentOrSelf(user, context); + RoleManagerCompat.setRoleFallbackEnabledAsUser(this, true, profileParent, context); + } else { + RoleManagerCompat.setRoleFallbackEnabledAsUser(this, true, user, context); + } } /** @@ -1107,7 +1123,8 @@ public class Role { // all users List<UserHandle> profiles = (crossUserRoleUxBugfixEnabled && getExclusivity() == EXCLUSIVITY_PROFILE_GROUP) - ? UserUtils.getUserProfiles(context, true) : List.of(user); + ? UserUtils.getUserProfiles(user, context, true) + : List.of(user); final int profilesSize = profiles.size(); for (int i = 0; i < profilesSize; i++) { UserHandle profile = profiles.get(i); diff --git a/PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java b/PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java index d00fd47af..1a0c83ab8 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java +++ b/PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java @@ -173,7 +173,7 @@ public class RoleControllerServiceImpl extends RoleControllerService { // or fallback holders, if any. currentPackageNames = mUserRoleManager.getRoleHolders(roleName); currentPackageNamesSize = currentPackageNames.size(); - boolean isStaticRole = role.isStatic(); + boolean isStaticRole = role.isStatic(mContext); if (currentPackageNamesSize == 0 || isStaticRole) { List<String> packageNamesToAdd = null; if (addedRoleNames.contains(roleName) || isStaticRole) { diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/UserUtils.java b/PermissionController/role-controller/java/com/android/role/controller/util/UserUtils.java index 00c05b17c..41233a23e 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/util/UserUtils.java +++ b/PermissionController/role-controller/java/com/android/role/controller/util/UserUtils.java @@ -139,14 +139,16 @@ public final class UserUtils { /** * Returns all the enabled user profiles on the device * + * @param user the {@link UserHandle} to get profiles for * @param context the {@link Context} * @param excludePrivate {@code true} to exclude private profiles from returned list of users */ @NonNull - public static List<UserHandle> getUserProfiles(@NonNull Context context, - boolean excludePrivate) { - UserManager userManager = context.getSystemService(UserManager.class); - List<UserHandle> profiles = userManager.getUserProfiles(); + public static List<UserHandle> getUserProfiles(@NonNull UserHandle user, + @NonNull Context context, boolean excludePrivate) { + Context userContext = getUserContext(context, user); + UserManager userUserManager = userContext.getSystemService(UserManager.class); + List<UserHandle> profiles = userUserManager.getUserProfiles(); if (!excludePrivate) { return profiles; } @@ -154,7 +156,7 @@ public final class UserUtils { final int profilesSize = profiles.size(); for (int i = 0; i < profilesSize; i++) { UserHandle profile = profiles.get(i); - if (!isPrivateProfile(profile, context)) { + if (!isPrivateProfile(profile, userContext)) { filteredProfiles.add(profile); } } diff --git a/PermissionController/src/com/android/permissioncontroller/ecm/EnhancedConfirmationDialogActivity.kt b/PermissionController/src/com/android/permissioncontroller/ecm/EnhancedConfirmationDialogActivity.kt index d3c7e3a0b..c5191938e 100644 --- a/PermissionController/src/com/android/permissioncontroller/ecm/EnhancedConfirmationDialogActivity.kt +++ b/PermissionController/src/com/android/permissioncontroller/ecm/EnhancedConfirmationDialogActivity.kt @@ -153,8 +153,8 @@ class EnhancedConfirmationDialogActivity : FragmentActivity() { var message: CharSequence? if (settingType == SettingType.BLOCKED_DUE_TO_PHONE_STATE) { title = settingType.titleRes?.let { context.getString(it) } - val messagePrefix = getPhoneStateMessagePrefix(context, settingIdentifier) - message = settingType.messageRes?.let { context.getString(it, messagePrefix) } + val settingMessage = getPhoneStateSettingMessage(context, settingIdentifier) + message = settingType.messageRes?.let { context.getString(it, settingMessage) } } else { val url = context.getString(R.string.help_url_action_disabled_by_restricted_settings) @@ -165,18 +165,17 @@ class EnhancedConfirmationDialogActivity : FragmentActivity() { return Setting(title, message) } - private fun getPhoneStateMessagePrefix( + private fun getPhoneStateSettingMessage( context: Context, settingsIdentifier: String, ): String { return context.getString( when (settingsIdentifier) { AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE -> - R.string.enhanced_confirmation_phone_state_dialog_a11y_desc_prefix + R.string.enhanced_confirmation_phone_state_dialog_a11y_desc AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES -> - R.string.enhanced_confirmation_phone_state_dialog_install_desc_prefix - else -> - R.string.enhanced_confirmation_phone_state_dialog_generic_desc_prefix + R.string.enhanced_confirmation_phone_state_dialog_install_desc + else -> R.string.enhanced_confirmation_phone_state_dialog_generic_desc } ) } @@ -278,7 +277,7 @@ class EnhancedConfirmationDialogActivity : FragmentActivity() { return AlertDialog.Builder(dialogActivity) .setView(createDialogView(dialogActivity, title, message)) - .setPositiveButton(R.string.enhanced_confirmation_dialog_ok) { _, _ -> + .setPositiveButton(R.string.dialog_close) { _, _ -> dialogActivity.onDialogResult(DialogResult.Okay) } .create() diff --git a/PermissionController/src/com/android/permissioncontroller/role/Role.md b/PermissionController/src/com/android/permissioncontroller/role/Role.md index 8d995d557..29a184190 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/Role.md +++ b/PermissionController/src/com/android/permissioncontroller/role/Role.md @@ -55,14 +55,13 @@ apps, separated by a colon (`:`) with the package name, for instance receive short text messages, photos, videos, and more". For default apps, this string will appear in the default app detail page as a footer. This attribute is required if the role is `visible`. - `exclusive`: Whether the role is exclusive. If a role is exclusive, at most one application is -allowed to be its holder. +allowed to be its holder. This attribute is being deprecated and `exclusivity` should be used. - `exclusivity`: Whether the role is exclusive and what type of exclusivity behavior it has. A role can have exclusivity of `none`, `user`, or `profileGroup`. - `none`: Role allows multiple holders - `user`: Role allows at most one holder within each user - - `profileGroup`: (SDK 36+ only, fallsback to `user` on lower SDK) Role allows at most one holder -within a profile group (e.g. full user and work -profile) + - `profileGroup`: (SDK 36+ only, falls back to `user` on lower SDK) Role allows at most one holder +within a profile group (e.g. full user and work profile) - `fallBackToDefaultHolder`: Whether the role should fall back to the default holder. This attribute is optional and defaults to `false`. - `featureFlag`: Optional feature flag for the role be available, as the fully qualified name of diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java index 268633c4f..814a312c6 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java @@ -16,6 +16,8 @@ package com.android.permissioncontroller.role.ui; +import static com.android.permissioncontroller.PermissionControllerStatsLog.ROLE_SETTINGS_FRAGMENT_ACTION_REPORTED; + import android.app.Activity; import android.app.role.RoleManager; import android.content.Context; @@ -41,6 +43,7 @@ import androidx.preference.TwoStatePreference; import com.android.modules.utils.build.SdkLevel; import com.android.permission.flags.Flags; +import com.android.permissioncontroller.PermissionControllerStatsLog; import com.android.permissioncontroller.R; import com.android.permissioncontroller.permission.utils.Utils; import com.android.permissioncontroller.role.utils.PackageUtils; @@ -48,6 +51,7 @@ import com.android.permissioncontroller.role.utils.RoleUiBehaviorUtils; import com.android.permissioncontroller.role.utils.SettingsCompat; import com.android.role.controller.model.Role; import com.android.role.controller.model.Roles; +import com.android.settingslib.utils.applications.AppUtils; import java.util.List; import java.util.Objects; @@ -77,8 +81,8 @@ public class DefaultAppChildFragment<PF extends PreferenceFragmentCompat DefaultAppChildFragment.class.getName() + ".preference.OTHER_NFC_SERVICES"; private static final String PREFERENCE_EXTRA_PACKAGE_NAME = DefaultAppChildFragment.class.getName() + ".extra.PACKAGE_NAME"; - private static final String PREFERENCE_EXTRA_USER = DefaultAppChildFragment.class.getName() - + ".extra.USER"; + private static final String PREFERENCE_EXTRA_UID = DefaultAppChildFragment.class.getName() + + ".extra.UID"; @NonNull private String mRoleName; @@ -302,10 +306,13 @@ public class DefaultAppChildFragment<PF extends PreferenceFragmentCompat // the `NONE` item passes a null applicationinfo object. NFC uses a different preference // method for adding, and a different onclick method if (applicationInfo != null) { + UserHandle user = UserHandle.getUserHandleForUid(applicationInfo.uid); + roleApplicationPreference.setContentDescription( + AppUtils.getAppContentDescription( + context, applicationInfo.packageName, user.getIdentifier())); Bundle extras = preference.getExtras(); extras.putString(PREFERENCE_EXTRA_PACKAGE_NAME, applicationInfo.packageName); - extras.putParcelable(PREFERENCE_EXTRA_USER, - UserHandle.getUserHandleForUid(applicationInfo.uid)); + extras.putInt(PREFERENCE_EXTRA_UID, applicationInfo.uid); } } else { preference = roleApplicationPreference.asTwoStatePreference(); @@ -348,24 +355,25 @@ public class DefaultAppChildFragment<PF extends PreferenceFragmentCompat } else { String packageName = preference.getExtras().getString(PREFERENCE_EXTRA_PACKAGE_NAME); - UserHandle user = - preference.getExtras().getParcelable(PREFERENCE_EXTRA_USER); + int uid = preference.getExtras().getInt(PREFERENCE_EXTRA_UID); CharSequence confirmationMessage = RoleUiBehaviorUtils.getConfirmationMessage(mRole, packageName, requireContext()); if (confirmationMessage != null) { - DefaultAppConfirmationDialogFragment.show(packageName, user, confirmationMessage, + DefaultAppConfirmationDialogFragment.show(packageName, uid, confirmationMessage, this); } else { - setDefaultApp(packageName, user); + setDefaultApp(packageName, uid); } } return true; } @Override - public void setDefaultApp(@NonNull String packageName, @NonNull UserHandle user) { - mViewModel.setDefaultApp(packageName, user); + public void setDefaultApp(@NonNull String packageName, int uid) { + PermissionControllerStatsLog.write( + ROLE_SETTINGS_FRAGMENT_ACTION_REPORTED, uid, packageName, mRoleName); + mViewModel.setDefaultApp(packageName, UserHandle.getUserHandleForUid(uid)); } private void addNonPaymentNfcServicesPreference(@NonNull PreferenceScreen preferenceScreen, diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppConfirmationDialogFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppConfirmationDialogFragment.java index 5f399a0b8..9a9606291 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppConfirmationDialogFragment.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppConfirmationDialogFragment.java @@ -20,11 +20,9 @@ import android.app.AlertDialog; import android.app.Dialog; import android.content.Intent; import android.os.Bundle; -import android.os.UserHandle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.core.os.BundleCompat; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; @@ -34,27 +32,27 @@ import androidx.fragment.app.Fragment; public class DefaultAppConfirmationDialogFragment extends DialogFragment { private String mPackageName; - private UserHandle mUser; + private int mUid; private CharSequence mMessage; /** * Create a new instance of this fragment. * * @param packageName the package name of the application - * @param user the user the specified package is running in + * @param uid the UID the specified package is running in * @param message the confirmation message * * @return a new instance of this fragment * - * @see #show(String, UserHandle, CharSequence, Fragment) + * @see #show(String, int, CharSequence, Fragment) */ @NonNull public static DefaultAppConfirmationDialogFragment newInstance(@NonNull String packageName, - @NonNull UserHandle user, @NonNull CharSequence message) { + int uid, @NonNull CharSequence message) { DefaultAppConfirmationDialogFragment fragment = new DefaultAppConfirmationDialogFragment(); Bundle arguments = new Bundle(); arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName); - arguments.putParcelable(Intent.EXTRA_USER, user); + arguments.putInt(Intent.EXTRA_UID, uid); arguments.putCharSequence(Intent.EXTRA_TEXT, message); fragment.setArguments(arguments); return fragment; @@ -64,15 +62,15 @@ public class DefaultAppConfirmationDialogFragment extends DialogFragment { * Show a new instance of this fragment. * * @param packageName the package name of the application - * @param user the user the specified package is running in + * @param uid the UID the specified package is running in * @param message the confirmation message * @param fragment the parent fragment * - * @see #newInstance(String, UserHandle, CharSequence) + * @see #newInstance(String, int, CharSequence) */ - public static void show(@NonNull String packageName, @NonNull UserHandle user, + public static void show(@NonNull String packageName, int uid, @NonNull CharSequence message, @NonNull Fragment fragment) { - newInstance(packageName, user, message).show(fragment.getChildFragmentManager(), null); + newInstance(packageName, uid, message).show(fragment.getChildFragmentManager(), null); } @Override @@ -81,7 +79,7 @@ public class DefaultAppConfirmationDialogFragment extends DialogFragment { Bundle arguments = getArguments(); mPackageName = arguments.getString(Intent.EXTRA_PACKAGE_NAME); - mUser = BundleCompat.getParcelable(arguments, Intent.EXTRA_USER, UserHandle.class); + mUid = arguments.getInt(Intent.EXTRA_UID); mMessage = arguments.getCharSequence(Intent.EXTRA_TEXT); } @@ -97,7 +95,7 @@ public class DefaultAppConfirmationDialogFragment extends DialogFragment { private void onOk() { Listener listener = (Listener) getParentFragment(); - listener.setDefaultApp(mPackageName, mUser); + listener.setDefaultApp(mPackageName, mUid); } /** @@ -110,6 +108,6 @@ public class DefaultAppConfirmationDialogFragment extends DialogFragment { * * @param packageName the package name of the application */ - void setDefaultApp(@NonNull String packageName, @NonNull UserHandle user); + void setDefaultApp(@NonNull String packageName, int uid); } } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java index 2a987167e..fd91d0d3b 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java @@ -40,10 +40,12 @@ import androidx.preference.PreferenceScreen; import com.android.modules.utils.build.SdkLevel; import com.android.permissioncontroller.R; import com.android.permissioncontroller.permission.utils.Utils; +import com.android.permissioncontroller.role.UserPackage; import com.android.permissioncontroller.role.utils.PackageUtils; import com.android.permissioncontroller.role.utils.RoleUiBehaviorUtils; import com.android.role.controller.model.Role; import com.android.role.controller.model.Roles; +import com.android.settingslib.utils.applications.AppUtils; import java.util.List; @@ -241,10 +243,16 @@ public class DefaultAppListChildFragment<PF extends PreferenceFragmentCompat if (holderApplicationInfos.isEmpty()) { preference.setIcon(null); preference.setSummary(R.string.default_app_none); + rolePreference.setSummaryContentDescription(null); } else { ApplicationInfo holderApplicationInfo = holderApplicationInfos.get(0); preference.setIcon(Utils.getBadgedIcon(context, holderApplicationInfo)); preference.setSummary(Utils.getAppLabel(holderApplicationInfo, context)); + UserPackage userPackage = UserPackage.from(holderApplicationInfo); + rolePreference.setSummaryContentDescription( + AppUtils.getAppContentDescription(context, + userPackage.packageName, + userPackage.user.getIdentifier())); } RoleUiBehaviorUtils.preparePreferenceAsUser(role, holderApplicationInfos, rolePreference, user, context); diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java index 4731c8b0f..89a17004b 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java @@ -59,6 +59,7 @@ import com.android.permissioncontroller.role.utils.UiUtils; import com.android.permissioncontroller.role.utils.UserUtils; import com.android.role.controller.model.Role; import com.android.role.controller.model.Roles; +import com.android.settingslib.utils.applications.AppUtils; import java.util.ArrayList; import java.util.List; @@ -698,6 +699,7 @@ public class RequestRoleFragment extends DialogFragment { Drawable icon; String title; String subtitle; + String contentDescription; if (applicationItem == null) { applicationInfo = null; restricted = false; @@ -706,6 +708,7 @@ public class RequestRoleFragment extends DialogFragment { title = context.getString(R.string.default_app_none); subtitle = mHolderUserPackage == null ? context.getString( R.string.request_role_current_default) : null; + contentDescription = null; } else { applicationInfo = applicationItem.getApplicationInfo(); UserPackage userPackage = UserPackage.from(applicationInfo); @@ -717,14 +720,18 @@ public class RequestRoleFragment extends DialogFragment { subtitle = applicationItem.isHolderApplication() ? context.getString(R.string.request_role_current_default) : checked ? context.getString(mRole.getRequestDescriptionResource()) : null; + contentDescription = AppUtils.getAppContentDescription(context, + userPackage.packageName, userPackage.user.getIdentifier()); } boolean enabled = isEnabled(position); UiUtils.setViewTreeEnabled(view, enabled && !restricted); view.setEnabled(enabled); view.setChecked(checked); + holder.iconImage.setImageDrawable(icon); holder.titleText.setText(title); + holder.titleText.setContentDescription(contentDescription); holder.subtitleText.setVisibility(!TextUtils.isEmpty(subtitle) ? View.VISIBLE : View.GONE); holder.subtitleText.setText(subtitle); diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleApplicationPreference.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleApplicationPreference.java index 1d3e32c9c..3336aad50 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/RoleApplicationPreference.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RoleApplicationPreference.java @@ -17,6 +17,7 @@ package com.android.permissioncontroller.role.ui; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.preference.TwoStatePreference; /** @@ -29,4 +30,9 @@ public interface RoleApplicationPreference extends RestrictionAwarePreference { */ @NonNull TwoStatePreference asTwoStatePreference(); + + /** + * Sets the preference's content description. + */ + void setContentDescription(@Nullable String contentDescription); } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/RolePreference.java b/PermissionController/src/com/android/permissioncontroller/role/ui/RolePreference.java index bbc123cfe..feafb0ae5 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/RolePreference.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/RolePreference.java @@ -17,6 +17,7 @@ package com.android.permissioncontroller.role.ui; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.preference.Preference; /** @@ -28,4 +29,9 @@ public interface RolePreference extends TwoTargetPreference, RestrictionAwarePre */ @NonNull Preference asPreference(); + + /** + * Sets the preference's summary content description. + */ + void setSummaryContentDescription(@Nullable String summaryContentDescription); } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoRadioPreference.java b/PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoRadioPreference.java index 764c07497..f0a27284d 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoRadioPreference.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoRadioPreference.java @@ -19,6 +19,7 @@ package com.android.permissioncontroller.role.ui.auto; import android.content.Context; import android.content.Intent; import android.widget.RadioButton; +import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -30,10 +31,15 @@ import com.android.permissioncontroller.R; import com.android.permissioncontroller.role.ui.RestrictionAwarePreferenceMixin; import com.android.permissioncontroller.role.ui.RoleApplicationPreference; +import java.util.Objects; + /** Preference used to represent apps that can be picked as a default app. */ public class AutoRadioPreference extends TwoStatePreference implements RoleApplicationPreference { + @Nullable + private String mContentDescription; + private final RestrictionAwarePreferenceMixin mRestrictionAwarePreferenceMixin = new RestrictionAwarePreferenceMixin(this); @@ -56,10 +62,21 @@ public class AutoRadioPreference extends TwoStatePreference implements RadioButton radioButton = (RadioButton) holder.findViewById(R.id.radio_button); radioButton.setChecked(isChecked()); + TextView titleText = (TextView) holder.findViewById(android.R.id.title); + titleText.setContentDescription(mContentDescription); + mRestrictionAwarePreferenceMixin.onAfterBindViewHolder(holder); } @Override + public void setContentDescription(@Nullable String contentDescription) { + if (!Objects.equals(mContentDescription, contentDescription)) { + mContentDescription = contentDescription; + notifyChanged(); + } + } + + @Override public void setRestrictionIntent(@Nullable Intent restrictionIntent) { mRestrictionAwarePreferenceMixin.setRestrictionIntent(restrictionIntent); } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoRolePreference.java b/PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoRolePreference.java index 15fd117d1..28dfc67f9 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoRolePreference.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoRolePreference.java @@ -19,6 +19,7 @@ package com.android.permissioncontroller.role.ui.auto; import android.content.Context; import android.content.Intent; import android.util.AttributeSet; +import android.widget.TextView; import androidx.annotation.AttrRes; import androidx.annotation.NonNull; @@ -31,12 +32,17 @@ import com.android.permissioncontroller.role.ui.RestrictionAwarePreferenceMixin; import com.android.permissioncontroller.role.ui.RolePreference; import com.android.permissioncontroller.role.ui.TwoTargetPreference; +import java.util.Objects; + /** * Preference for use in auto lists. Extends {@link TwoTargetPreference} in order to make sure of * shared logic between phone and auto settings UI. */ public class AutoRolePreference extends Preference implements RolePreference { + @Nullable + private String mSummaryContentDescription; + private RestrictionAwarePreferenceMixin mRestrictionAwarePreferenceMixin = new RestrictionAwarePreferenceMixin(this); @@ -62,6 +68,14 @@ public class AutoRolePreference extends Preference implements RolePreference { public void setOnSecondTargetClickListener(@Nullable OnSecondTargetClickListener listener) {} @Override + public void setSummaryContentDescription(@Nullable String summaryContentDescription) { + if (!Objects.equals(mSummaryContentDescription, summaryContentDescription)) { + mSummaryContentDescription = summaryContentDescription; + notifyChanged(); + } + } + + @Override public void setRestrictionIntent(@Nullable Intent restrictionIntent) { mRestrictionAwarePreferenceMixin.setRestrictionIntent(restrictionIntent); } @@ -70,6 +84,9 @@ public class AutoRolePreference extends Preference implements RolePreference { public void onBindViewHolder(@NonNull PreferenceViewHolder holder) { super.onBindViewHolder(holder); + TextView summaryText = (TextView) holder.findViewById(android.R.id.summary); + summaryText.setContentDescription(mSummaryContentDescription); + mRestrictionAwarePreferenceMixin.onAfterBindViewHolder(holder); } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoSwitchPreference.java b/PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoSwitchPreference.java index bfb2b5d1d..e7279278c 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoSwitchPreference.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoSwitchPreference.java @@ -19,6 +19,7 @@ package com.android.permissioncontroller.role.ui.auto; import android.content.Context; import android.content.Intent; import android.util.AttributeSet; +import android.widget.TextView; import androidx.annotation.AttrRes; import androidx.annotation.NonNull; @@ -30,12 +31,16 @@ import androidx.preference.SwitchPreference; import com.android.permissioncontroller.role.ui.RestrictionAwarePreferenceMixin; import com.android.permissioncontroller.role.ui.RoleApplicationPreference; +import java.util.Objects; + /** * Role application preference represented as a switch. */ public class AutoSwitchPreference extends SwitchPreference implements RoleApplicationPreference { + @Nullable + private String mContentDescription; private RestrictionAwarePreferenceMixin mRestrictionAwarePreferenceMixin = new RestrictionAwarePreferenceMixin(this); @@ -58,6 +63,14 @@ public class AutoSwitchPreference extends SwitchPreference } @Override + public void setContentDescription(@Nullable String contentDescription) { + if (!Objects.equals(mContentDescription, contentDescription)) { + mContentDescription = contentDescription; + notifyChanged(); + } + } + + @Override public void setRestrictionIntent(@Nullable Intent restrictionIntent) { mRestrictionAwarePreferenceMixin.setRestrictionIntent(restrictionIntent); } @@ -66,6 +79,9 @@ public class AutoSwitchPreference extends SwitchPreference public void onBindViewHolder(@NonNull PreferenceViewHolder holder) { super.onBindViewHolder(holder); + TextView titleText = (TextView) holder.findViewById(android.R.id.title); + titleText.setContentDescription(mContentDescription); + mRestrictionAwarePreferenceMixin.onAfterBindViewHolder(holder); } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/v35/WalletRoleUiBehavior.java b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/v35/WalletRoleUiBehavior.java index 09aaa0532..eb1dbb5ef 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/v35/WalletRoleUiBehavior.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/behavior/v35/WalletRoleUiBehavior.java @@ -42,6 +42,7 @@ import androidx.core.util.Pair; import androidx.preference.Preference; import com.android.launcher3.icons.IconFactory; +import com.android.permissioncontroller.role.ui.RequestRoleItemView; import com.android.permissioncontroller.role.ui.TwoTargetPreference; import com.android.permissioncontroller.role.ui.behavior.RoleUiBehavior; import com.android.role.controller.model.Role; @@ -73,6 +74,21 @@ public class WalletRoleUiBehavior implements RoleUiBehavior { } @Override + public void prepareRequestRoleItemViewAsUser(@NonNull Role role, + @NonNull RequestRoleItemView itemView, @NonNull ApplicationInfo applicationInfo, + @NonNull UserHandle user, @NonNull Context context) { + if (isSystemApplication(applicationInfo)) { + Pair<Drawable, CharSequence> bannerAndLabel = getLabelAndIconIfItExists( + applicationInfo, user, context); + + if (bannerAndLabel != null) { + itemView.getIconImageView().setImageDrawable(bannerAndLabel.first); + itemView.getTitleTextView().setText(bannerAndLabel.second); + } + } + } + + @Override public void prepareApplicationPreferenceAsUser(@NonNull Role role, @NonNull Preference preference, @NonNull ApplicationInfo applicationInfo, @NonNull UserHandle user, @NonNull Context context) { @@ -84,21 +100,8 @@ public class WalletRoleUiBehavior implements RoleUiBehavior { @NonNull ApplicationInfo applicationInfo, boolean setTitle, @NonNull UserHandle user, @NonNull Context context) { if (isSystemApplication(applicationInfo)) { - List<ApduServiceInfo> serviceInfos = getNfcServicesForPackage( - applicationInfo.packageName, user, context); - - Pair<Drawable, CharSequence> bannerAndLabel = null; - // If the flag is enabled , attempt to fetch it from property - if (Flags.walletRoleIconPropertyEnabled()) { - bannerAndLabel = - getBannerAndLabelFromPackageProperty(context, user, - applicationInfo.packageName); - } - // If it's null, indicating that the property is not set, perform a legacy icon lookup. - if (bannerAndLabel == null) { - bannerAndLabel = - getNonPaymentServiceBannerAndLabelIfExists(serviceInfos, user, context); - } + Pair<Drawable, CharSequence> bannerAndLabel = getLabelAndIconIfItExists( + applicationInfo, user, context); if (bannerAndLabel != null) { preference.setIcon(bannerAndLabel.first); if (setTitle) { @@ -110,6 +113,26 @@ public class WalletRoleUiBehavior implements RoleUiBehavior { } } + @Nullable + private Pair<Drawable, CharSequence> getLabelAndIconIfItExists( + @NonNull ApplicationInfo applicationInfo, + @NonNull UserHandle user, + @NonNull Context context) { + Pair<Drawable, CharSequence> result = null; + // If the flag is enabled , attempt to fetch it from property + if (Flags.walletRoleIconPropertyEnabled()) { + result = getBannerAndLabelFromPackageProperty(context, user, + applicationInfo.packageName); + } + if (result != null) { + return result; + } + List<ApduServiceInfo> serviceInfos = getNfcServicesForPackage( + applicationInfo.packageName, user, context); + // If it's null, indicating that the property is not set, perform a legacy icon lookup. + return getNonPaymentServiceBannerAndLabelIfExists(serviceInfos, user, context); + } + @Nullable private Pair<Drawable, CharSequence> getBannerAndLabelFromPackageProperty( diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/handheld/HandheldRadioPreference.java b/PermissionController/src/com/android/permissioncontroller/role/ui/handheld/HandheldRadioPreference.java index 67f04051c..2a943d3d7 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/handheld/HandheldRadioPreference.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/handheld/HandheldRadioPreference.java @@ -19,6 +19,7 @@ package com.android.permissioncontroller.role.ui.handheld; import android.content.Context; import android.content.Intent; import android.util.AttributeSet; +import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -28,12 +29,17 @@ import com.android.permissioncontroller.role.ui.RestrictionAwarePreferenceMixin; import com.android.permissioncontroller.role.ui.RoleApplicationPreference; import com.android.settingslib.widget.SelectorWithWidgetPreference; +import java.util.Objects; + /** * Preference used to represent apps that can be picked as a default app. */ public class HandheldRadioPreference extends SelectorWithWidgetPreference implements RoleApplicationPreference { + @Nullable + private String mContentDescription; + private final RestrictionAwarePreferenceMixin mRestrictionAwarePreferenceMixin = new RestrictionAwarePreferenceMixin(this); @@ -56,6 +62,14 @@ public class HandheldRadioPreference extends SelectorWithWidgetPreference implem } @Override + public void setContentDescription(@Nullable String contentDescription) { + if (!Objects.equals(mContentDescription, contentDescription)) { + mContentDescription = contentDescription; + notifyChanged(); + } + } + + @Override public void setRestrictionIntent(@Nullable Intent restrictionIntent) { mRestrictionAwarePreferenceMixin.setRestrictionIntent(restrictionIntent); } @@ -64,6 +78,9 @@ public class HandheldRadioPreference extends SelectorWithWidgetPreference implem public void onBindViewHolder(@NonNull PreferenceViewHolder holder) { super.onBindViewHolder(holder); + TextView titleText = (TextView) holder.findViewById(android.R.id.title); + titleText.setContentDescription(mContentDescription); + mRestrictionAwarePreferenceMixin.onAfterBindViewHolder(holder); } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/handheld/HandheldRolePreference.java b/PermissionController/src/com/android/permissioncontroller/role/ui/handheld/HandheldRolePreference.java index 3d09f0b46..46bf3b173 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/handheld/HandheldRolePreference.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/handheld/HandheldRolePreference.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.Intent; import android.util.AttributeSet; import android.view.View; +import android.widget.TextView; import androidx.annotation.AttrRes; import androidx.annotation.NonNull; @@ -33,6 +34,8 @@ import com.android.permissioncontroller.role.ui.RestrictionAwarePreferenceMixin; import com.android.permissioncontroller.role.ui.RolePreference; import com.android.settingslib.widget.TwoTargetPreference; +import java.util.Objects; + /** * {@link Preference} with a settings button. * @@ -45,6 +48,9 @@ public class HandheldRolePreference extends TwoTargetPreference implements RoleP new RestrictionAwarePreferenceMixin(this); @Nullable + private String mSummaryContentDescription; + + @Nullable private OnSecondTargetClickListener mOnSecondTargetClickListener; public HandheldRolePreference(@NonNull Context context, @Nullable AttributeSet attrs, @@ -94,6 +100,14 @@ public class HandheldRolePreference extends TwoTargetPreference implements RoleP } @Override + public void setSummaryContentDescription(@Nullable String summaryContentDescription) { + if (!Objects.equals(mSummaryContentDescription, summaryContentDescription)) { + mSummaryContentDescription = summaryContentDescription; + notifyChanged(); + } + } + + @Override public void setRestrictionIntent(@Nullable Intent restrictionIntent) { mRestrictionAwarePreferenceMixin.setRestrictionIntent(restrictionIntent); } @@ -114,6 +128,9 @@ public class HandheldRolePreference extends TwoTargetPreference implements RoleP // Make the settings button enabled even if the preference itself is disabled. settingsButton.setEnabled(true); + TextView summaryText = (TextView) holder.findViewById(android.R.id.summary); + summaryText.setContentDescription(mSummaryContentDescription); + mRestrictionAwarePreferenceMixin.onAfterBindViewHolder(holder); } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/handheld/HandheldSwitchPreference.java b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/handheld/HandheldSwitchPreference.java index ded6d5cb5..a801c2182 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/handheld/HandheldSwitchPreference.java +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/handheld/HandheldSwitchPreference.java @@ -19,6 +19,7 @@ package com.android.permissioncontroller.role.ui.specialappaccess.handheld; import android.content.Context; import android.content.Intent; import android.util.AttributeSet; +import android.widget.TextView; import androidx.annotation.AttrRes; import androidx.annotation.NonNull; @@ -30,10 +31,14 @@ import com.android.permissioncontroller.role.ui.RestrictionAwarePreferenceMixin; import com.android.permissioncontroller.role.ui.RoleApplicationPreference; import com.android.settingslib.widget.AppSwitchPreference; +import java.util.Objects; + /** {@link AppSwitchPreference} that is a role application preference. */ public class HandheldSwitchPreference extends AppSwitchPreference implements RoleApplicationPreference { + @Nullable + private String mContentDescription; private RestrictionAwarePreferenceMixin mRestrictionAwarePreferenceMixin = new RestrictionAwarePreferenceMixin(this); @@ -56,6 +61,14 @@ public class HandheldSwitchPreference extends AppSwitchPreference } @Override + public void setContentDescription(@Nullable String contentDescription) { + if (!Objects.equals(mContentDescription, contentDescription)) { + mContentDescription = contentDescription; + notifyChanged(); + } + } + + @Override public void setRestrictionIntent(@Nullable Intent restrictionIntent) { mRestrictionAwarePreferenceMixin.setRestrictionIntent(restrictionIntent); } @@ -64,6 +77,9 @@ public class HandheldSwitchPreference extends AppSwitchPreference public void onBindViewHolder(@NonNull PreferenceViewHolder holder) { super.onBindViewHolder(holder); + TextView titleText = (TextView) holder.findViewById(android.R.id.title); + titleText.setContentDescription(mContentDescription); + mRestrictionAwarePreferenceMixin.onAfterBindViewHolder(holder); } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRoleApplicationPreference.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRoleApplicationPreference.kt index 6cd52f576..cb12bf70a 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRoleApplicationPreference.kt +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRoleApplicationPreference.kt @@ -18,6 +18,7 @@ package com.android.permissioncontroller.role.ui.wear import android.content.Context import android.content.Intent +import androidx.preference.PreferenceViewHolder import androidx.preference.TwoStatePreference import com.android.permissioncontroller.role.ui.RoleApplicationPreference @@ -30,7 +31,8 @@ class WearRoleApplicationPreference( defaultLabel: String, val checked: Boolean, val onDefaultCheckChanged: (Boolean) -> Unit = {}, - private var restrictionIntent: Intent? = null + private var restrictionIntent: Intent? = null, + private var contentDescription: String? = null, ) : TwoStatePreference(context), RoleApplicationPreference { init { title = defaultLabel @@ -39,10 +41,22 @@ class WearRoleApplicationPreference( fun getOnCheckChanged(): (Boolean) -> Unit = restrictionIntent?.let { { _ -> context.startActivity(it) } } ?: onDefaultCheckChanged + override fun setContentDescription(contentDescription: String?) { + if (this.contentDescription != contentDescription) { + this.contentDescription = contentDescription + notifyChanged() + } + } + override fun setRestrictionIntent(restrictionIntent: Intent?) { this.restrictionIntent = restrictionIntent isEnabled = restrictionIntent == null } override fun asTwoStatePreference(): TwoStatePreference = this + + override fun onBindViewHolder(holder: PreferenceViewHolder) { + super.onBindViewHolder(holder) + holder.findViewById(android.R.id.title)?.let { it.contentDescription = contentDescription } + } } diff --git a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRolePreference.kt b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRolePreference.kt index 43acf4293..670c136ea 100644 --- a/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRolePreference.kt +++ b/PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRolePreference.kt @@ -19,6 +19,7 @@ package com.android.permissioncontroller.role.ui.wear import android.content.Context import android.content.Intent import androidx.preference.Preference +import androidx.preference.PreferenceViewHolder import com.android.permissioncontroller.role.ui.RolePreference import com.android.permissioncontroller.role.ui.TwoTargetPreference.OnSecondTargetClickListener import com.android.settingslib.widget.TwoTargetPreference @@ -28,13 +29,21 @@ class WearRolePreference( context: Context, val label: String, val onDefaultClicked: () -> Unit = {}, - private var restrictionIntent: Intent? = null + private var restrictionIntent: Intent? = null, + private var summaryContentDescription: String? = null, ) : TwoTargetPreference(context), RolePreference { override fun setOnSecondTargetClickListener(listener: OnSecondTargetClickListener?) { // no-op } + override fun setSummaryContentDescription(summaryContentDescription: String?) { + if (this.summaryContentDescription != summaryContentDescription) { + this.summaryContentDescription = summaryContentDescription + notifyChanged() + } + } + override fun setRestrictionIntent(restrictionIntent: Intent?) { this.restrictionIntent = restrictionIntent setEnabled(restrictionIntent == null) @@ -42,6 +51,14 @@ class WearRolePreference( override fun asPreference(): Preference = this + override fun onBindViewHolder(holder: PreferenceViewHolder) { + super.onBindViewHolder(holder) + + holder.findViewById(android.R.id.summary)?.let { + it.contentDescription = summaryContentDescription + } + } + fun getOnClicked(): () -> Unit = restrictionIntent?.let { { context.startActivity(it) } } ?: onDefaultClicked } diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterFragment.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterFragment.kt index b5a66da06..d29b0aa3e 100644 --- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterFragment.kt +++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterFragment.kt @@ -61,7 +61,6 @@ abstract class SafetyCenterFragment : SettingsBasePreferenceFragment() { } else { super.onCreateAdapter(preferenceScreen) } - /* By default, the PreferenceGroupAdapter does setHasStableIds(true). Since each Preference * is internally allocated with an auto-incremented ID, it does not allow us to gracefully * update only changed preferences based on SafetyPreferenceComparisonCallback. In order to @@ -77,10 +76,15 @@ abstract class SafetyCenterFragment : SettingsBasePreferenceFragment() { .split(",") safetyCenterSessionId = requireArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID) + val activity = requireActivity() safetyCenterViewModel = ViewModelProvider( - requireActivity(), - LiveSafetyCenterViewModelFactory(requireActivity().getApplication()), + activity, + LiveSafetyCenterViewModelFactory( + activity.application, + activity.taskId, + sameTaskSourceIds, + ), ) .get(SafetyCenterViewModel::class.java) safetyCenterViewModel.safetyCenterUiLiveData.observe(this) { uiData: SafetyCenterUiData? -> @@ -91,8 +95,7 @@ abstract class SafetyCenterFragment : SettingsBasePreferenceFragment() { displayErrorDetails(errorDetails) } - val safetyCenterIntent: ParsedSafetyCenterIntent = - requireActivity().intent.toSafetyCenterIntent() + val safetyCenterIntent: ParsedSafetyCenterIntent = activity.intent.toSafetyCenterIntent() val isQsFragment = getArguments()?.getBoolean(QUICK_SETTINGS_SAFETY_CENTER_FRAGMENT, false) ?: false collapsableIssuesCardHelper = diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/IssueUiData.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/IssueUiData.kt new file mode 100644 index 000000000..e260bb917 --- /dev/null +++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/IssueUiData.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.permissioncontroller.safetycenter.ui.model + +import android.safetycenter.SafetyCenterIssue + +/** UI model representation of [SafetyCenterIssue] */ +data class IssueUiData( + val issue: SafetyCenterIssue, + val isDismissed: Boolean, + val resolvedIssueActionId: String? = null, + val launchTaskId: Int? = null, +) diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt index 4ddcf1c3d..0b976f49d 100644 --- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt +++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt @@ -43,11 +43,16 @@ import com.android.safetycenter.internaldata.SafetyCenterIds /* A SafetyCenterViewModel that talks to the real backing service for Safety Center. */ @RequiresApi(Build.VERSION_CODES.TIRAMISU) -class LiveSafetyCenterViewModel(app: Application) : SafetyCenterViewModel(app) { +class LiveSafetyCenterViewModel( + app: Application, + private val taskId: Int, + private val sameTaskSourceIds: List<String>, +) : SafetyCenterViewModel(app) { private val TAG: String = LiveSafetyCenterViewModel::class.java.simpleName override val statusUiLiveData: LiveData<StatusUiData> get() = safetyCenterUiLiveData.map { StatusUiData(it.safetyCenterData) } + override val safetyCenterUiLiveData: LiveData<SafetyCenterUiData> by this::_safetyCenterLiveData override val errorLiveData: LiveData<SafetyCenterErrorDetails> by this::_errorLiveData @@ -65,7 +70,7 @@ class LiveSafetyCenterViewModel(app: Application) : SafetyCenterViewModel(app) { private val safetyCenterManager = app.getSystemService(SafetyCenterManager::class.java)!! override fun getCurrentSafetyCenterDataAsUiData(): SafetyCenterUiData = - SafetyCenterUiData(safetyCenterManager.safetyCenterData) + uiData(safetyCenterManager.safetyCenterData) override fun dismissIssue(issue: SafetyCenterIssue) { safetyCenterManager.dismissSafetyCenterIssue(issue.id) @@ -74,7 +79,7 @@ class LiveSafetyCenterViewModel(app: Application) : SafetyCenterViewModel(app) { override fun executeIssueAction( issue: SafetyCenterIssue, action: SafetyCenterIssue.Action, - launchTaskId: Int? + launchTaskId: Int?, ) { val issueId = if (launchTaskId != null) { @@ -107,9 +112,7 @@ class LiveSafetyCenterViewModel(app: Application) : SafetyCenterViewModel(app) { override fun navigateToSafetyCenter(context: Context, navigationSource: NavigationSource?) { val intent = Intent(ACTION_SAFETY_CENTER) - if (navigationSource != null) { - navigationSource.addToIntent(intent) - } + navigationSource?.addToIntent(intent) context.startActivity(intent) } @@ -132,7 +135,7 @@ class LiveSafetyCenterViewModel(app: Application) : SafetyCenterViewModel(app) { } else { safetyCenterManager.refreshSafetySources( SafetyCenterManager.REFRESH_REASON_PAGE_OPEN, - safetySourceIds + safetySourceIds, ) } } @@ -174,7 +177,7 @@ class LiveSafetyCenterViewModel(app: Application) : SafetyCenterViewModel(app) { override fun onActive() { safetyCenterManager.addOnSafetyCenterDataChangedListener( getMainExecutor(app.applicationContext), - this + this, ) super.onActive() } @@ -209,7 +212,7 @@ class LiveSafetyCenterViewModel(app: Application) : SafetyCenterViewModel(app) { Log.d( TAG, "Received SafetyCenterData while issue resolution animations" + - " occurring. Will update UI with new data soon." + " occurring. Will update UI with new data soon.", ) return } @@ -254,7 +257,7 @@ class LiveSafetyCenterViewModel(app: Application) : SafetyCenterViewModel(app) { private fun isCurrentlyScanning(): Boolean = value?.safetyCenterData?.isScanning() ?: false private fun sendNextData() { - value = SafetyCenterUiData(safetyCenterDataQueue.removeFirst()) + value = uiData(safetyCenterDataQueue.removeFirst()) } private fun skipNextData() = safetyCenterDataQueue.removeFirst() @@ -270,7 +273,7 @@ class LiveSafetyCenterViewModel(app: Application) : SafetyCenterViewModel(app) { // The current SafetyCenterData still contains the resolved SafetyCenterIssue objects. // Send it with the resolved IDs so the UI can generate the correct preferences and // trigger the right animations for issue resolution. - value = SafetyCenterUiData(currentData, currentResolvedIssues) + value = uiData(currentData, currentResolvedIssues) } @MainThread @@ -279,6 +282,11 @@ class LiveSafetyCenterViewModel(app: Application) : SafetyCenterViewModel(app) { maybeProcessDataToNextResolvedIssues() } } + + private fun uiData( + safetyCenterData: SafetyCenterData, + resolvedIssues: Map<IssueId, ActionId> = emptyMap(), + ) = SafetyCenterUiData(safetyCenterData, taskId, sameTaskSourceIds, resolvedIssues) } /** Returns inflight issues pending resolution */ @@ -309,8 +317,15 @@ private val SafetyCenterData.allResolvableIssues: Sequence<SafetyCenterIssue> } @RequiresApi(Build.VERSION_CODES.TIRAMISU) -class LiveSafetyCenterViewModelFactory(private val app: Application) : ViewModelProvider.Factory { +class LiveSafetyCenterViewModelFactory +@JvmOverloads +constructor( + private val app: Application, + private val taskId: Int = 0, + private val sameTaskSourceIds: List<String> = emptyList(), +) : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>): T { - @Suppress("UNCHECKED_CAST") return LiveSafetyCenterViewModel(app) as T + @Suppress("UNCHECKED_CAST") + return LiveSafetyCenterViewModel(app, taskId, sameTaskSourceIds) as T } } diff --git a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterUiData.kt b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterUiData.kt index 69a315f08..d8aadae2f 100644 --- a/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterUiData.kt +++ b/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterUiData.kt @@ -29,11 +29,21 @@ import com.android.safetycenter.internaldata.SafetyCenterIds import com.android.safetycenter.internaldata.SafetyCenterIssueKey /** UI model representation of Safety Center Data */ +@RequiresApi(TIRAMISU) data class SafetyCenterUiData( val safetyCenterData: SafetyCenterData, - val resolvedIssues: Map<IssueId, ActionId> = emptyMap() + private val taskId: Int, + private val sameTaskSourceIds: List<String>, + val resolvedIssues: Map<IssueId, ActionId> = emptyMap(), ) { - @RequiresApi(TIRAMISU) + + val issueUiDatas: List<IssueUiData> by + lazy(LazyThreadSafetyMode.NONE) { + safetyCenterData.issues.map { + IssueUiData(it, false, resolvedIssues[it.id], getLaunchTaskIdForIssue(it)) + } + } + fun getMatchingIssue(issueKey: SafetyCenterIssueKey): SafetyCenterIssue? { return safetyCenterData.issues.find { SafetyCenterIds.issueIdFromString(it.id).safetyCenterIssueKey == issueKey @@ -67,7 +77,7 @@ data class SafetyCenterUiData( @RequiresApi(UPSIDE_DOWN_CAKE) private fun selectMatchingIssuesForGroup( groupId: String, - issues: List<SafetyCenterIssue> + issues: List<SafetyCenterIssue>, ): List<SafetyCenterIssue> { val issuesToGroups = safetyCenterData.extras.getBundle(ISSUES_TO_GROUPS_BUNDLE_KEY) return issues.filter { @@ -84,4 +94,12 @@ data class SafetyCenterUiData( @RequiresApi(UPSIDE_DOWN_CAKE) fun SafetyCenterData.visibleDismissedIssues() = dismissedIssues.filter { it.severityLevel > ISSUE_SEVERITY_LEVEL_OK } + + private fun getLaunchTaskIdForIssue(issue: SafetyCenterIssue): Int? { + val sourceId: String = + SafetyCenterIds.issueIdFromString(issue.id) + .getSafetyCenterIssueKey() + .getSafetySourceId() + return if (sameTaskSourceIds.contains(sourceId)) taskId else null + } } diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/model/SafetyCenterUiDataTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/model/SafetyCenterUiDataTest.kt index ca0392716..e53fabc90 100644 --- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/model/SafetyCenterUiDataTest.kt +++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/model/SafetyCenterUiDataTest.kt @@ -18,6 +18,7 @@ package com.android.permissioncontroller.tests.mocking.safetycenter.ui.model import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE import android.os.Bundle +import android.os.UserHandle import android.safetycenter.SafetyCenterData import android.safetycenter.SafetyCenterEntryGroup import android.safetycenter.SafetyCenterEntryOrGroup @@ -28,8 +29,14 @@ import android.safetycenter.SafetyCenterIssue.ISSUE_SEVERITY_LEVEL_RECOMMENDATIO import android.safetycenter.SafetyCenterStatus import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SdkSuppress +import com.android.permissioncontroller.safetycenter.ui.model.ActionId +import com.android.permissioncontroller.safetycenter.ui.model.IssueId +import com.android.permissioncontroller.safetycenter.ui.model.IssueUiData import com.android.permissioncontroller.safetycenter.ui.model.SafetyCenterUiData import com.android.safetycenter.internaldata.SafetyCenterBundles.ISSUES_TO_GROUPS_BUNDLE_KEY +import com.android.safetycenter.internaldata.SafetyCenterIds +import com.android.safetycenter.internaldata.SafetyCenterIssueId +import com.android.safetycenter.internaldata.SafetyCenterIssueKey import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith @@ -40,42 +47,42 @@ class SafetyCenterUiDataTest { @Test fun getMatchingGroup_validMatchingGroup_returnsExpectedEntryGroup() { - val matchingGroup = createSafetyCenterEntryGroup(MATCHING_GROUP_ID) - val nonMatchingGroup = createSafetyCenterEntryGroup(NON_MATCHING_GROUP_ID) + val matchingGroup = entryGroup(MATCHING_GROUP_ID) + val nonMatchingGroup = entryGroup(NON_MATCHING_GROUP_ID) val safetyCenterData = createSafetyCenterData(entryGroups = listOf(matchingGroup, nonMatchingGroup)) - val result = SafetyCenterUiData(safetyCenterData).getMatchingGroup(MATCHING_GROUP_ID) + val result = uiData(safetyCenterData).getMatchingGroup(MATCHING_GROUP_ID) assertThat(result).isEqualTo(matchingGroup) } @Test fun getMatchingGroup_noMatchingGroup_returnsNull() { - val nonMatchingGroup = createSafetyCenterEntryGroup(NON_MATCHING_GROUP_ID) + val nonMatchingGroup = entryGroup(NON_MATCHING_GROUP_ID) val safetyCenterData = createSafetyCenterData(entryGroups = listOf(nonMatchingGroup)) - val result = SafetyCenterUiData(safetyCenterData).getMatchingGroup(MATCHING_GROUP_ID) + val result = uiData(safetyCenterData).getMatchingGroup(MATCHING_GROUP_ID) assertThat(result).isNull() } @Test fun getMatchingIssues_defaultMatchingIssue_noExtras_returnsListOfIssues() { - val defaultMatchingIssue = createSafetyCenterIssue("id1", MATCHING_GROUP_ID) - val nonMatchingIssue = createSafetyCenterIssue("id2", NON_MATCHING_GROUP_ID) + val defaultMatchingIssue = issue("id1", MATCHING_GROUP_ID) + val nonMatchingIssue = issue("id2", NON_MATCHING_GROUP_ID) val safetyCenterData = createSafetyCenterData(issues = listOf(defaultMatchingIssue, nonMatchingIssue)) - val result = SafetyCenterUiData(safetyCenterData).getMatchingIssues(MATCHING_GROUP_ID) + val result = uiData(safetyCenterData).getMatchingIssues(MATCHING_GROUP_ID) assertThat(result).containsExactly(defaultMatchingIssue) } @Test fun getMatchingIssues_defaultMatchingIssue_unrelatedExtras_returnsListOfIssues() { - val defaultMatchingIssue = createSafetyCenterIssue("id1", MATCHING_GROUP_ID) - val nonMatchingIssue = createSafetyCenterIssue("id2", NON_MATCHING_GROUP_ID) + val defaultMatchingIssue = issue("id1", MATCHING_GROUP_ID) + val nonMatchingIssue = issue("id2", NON_MATCHING_GROUP_ID) val safetyCenterData = createSafetyCenterData( issues = listOf(defaultMatchingIssue, nonMatchingIssue), @@ -84,21 +91,21 @@ class SafetyCenterUiDataTest { Bundle().apply { putStringArrayList( nonMatchingIssue.id, - arrayListOf(NON_MATCHING_GROUP_ID) + arrayListOf(NON_MATCHING_GROUP_ID), ) } - ) + ), ) - val result = SafetyCenterUiData(safetyCenterData).getMatchingIssues(MATCHING_GROUP_ID) + val result = uiData(safetyCenterData).getMatchingIssues(MATCHING_GROUP_ID) assertThat(result).containsExactly(defaultMatchingIssue) } @Test fun getMatchingIssues_mappingMatchingIssue_returnsListOfIssues() { - val mappingMatchingIssue = createSafetyCenterIssue("id1", NON_MATCHING_GROUP_ID) - val nonMatchingIssue = createSafetyCenterIssue("id2", NON_MATCHING_GROUP_ID) + val mappingMatchingIssue = issue("id1", NON_MATCHING_GROUP_ID) + val nonMatchingIssue = issue("id2", NON_MATCHING_GROUP_ID) val safetyCenterData = createSafetyCenterData( issues = listOf(mappingMatchingIssue, nonMatchingIssue), @@ -107,51 +114,50 @@ class SafetyCenterUiDataTest { Bundle().apply { putStringArrayList( mappingMatchingIssue.id, - arrayListOf(MATCHING_GROUP_ID) + arrayListOf(MATCHING_GROUP_ID), ) } - ) + ), ) - val result = SafetyCenterUiData(safetyCenterData).getMatchingIssues(MATCHING_GROUP_ID) + val result = uiData(safetyCenterData).getMatchingIssues(MATCHING_GROUP_ID) assertThat(result).containsExactly(mappingMatchingIssue) } @Test fun getMatchingIssues_noDefaultMatchingIssue_returnsEmptyList() { - val nonMatchingIssue = createSafetyCenterIssue("id1", NON_MATCHING_GROUP_ID) - val dismissedIssue = createSafetyCenterIssue("id2", MATCHING_GROUP_ID) + val nonMatchingIssue = issue("id1", NON_MATCHING_GROUP_ID) + val dismissedIssue = issue("id2", MATCHING_GROUP_ID) val safetyCenterData = createSafetyCenterData( issues = listOf(nonMatchingIssue), - dismissedIssues = listOf(dismissedIssue) + dismissedIssues = listOf(dismissedIssue), ) - val result = SafetyCenterUiData(safetyCenterData).getMatchingIssues(MATCHING_GROUP_ID) + val result = uiData(safetyCenterData).getMatchingIssues(MATCHING_GROUP_ID) assertThat(result).isEmpty() } @Test fun getMatchingDismissedIssues_defaultMatchingDismissedIssue_returnsListOfDismissedIssues() { - val defaultMatchingDismissedIssue = createSafetyCenterIssue("id1", MATCHING_GROUP_ID) - val nonMatchingDismissedIssue = createSafetyCenterIssue("id2", NON_MATCHING_GROUP_ID) + val defaultMatchingDismissedIssue = issue("id1", MATCHING_GROUP_ID) + val nonMatchingDismissedIssue = issue("id2", NON_MATCHING_GROUP_ID) val safetyCenterData = createSafetyCenterData( dismissedIssues = listOf(defaultMatchingDismissedIssue, nonMatchingDismissedIssue) ) - val result = - SafetyCenterUiData(safetyCenterData).getMatchingDismissedIssues(MATCHING_GROUP_ID) + val result = uiData(safetyCenterData).getMatchingDismissedIssues(MATCHING_GROUP_ID) assertThat(result).containsExactly(defaultMatchingDismissedIssue) } @Test fun getMatchingDismissedIssues_defaultMatchingDismissedIssue2_returnsListOfDismissedIssues() { - val defaultMatchingDismissedIssue = createSafetyCenterIssue("id1", MATCHING_GROUP_ID) - val nonMatchingDismissedIssue = createSafetyCenterIssue("id2", NON_MATCHING_GROUP_ID) + val defaultMatchingDismissedIssue = issue("id1", MATCHING_GROUP_ID) + val nonMatchingDismissedIssue = issue("id2", NON_MATCHING_GROUP_ID) val safetyCenterData = createSafetyCenterData( dismissedIssues = listOf(defaultMatchingDismissedIssue, nonMatchingDismissedIssue), @@ -160,22 +166,21 @@ class SafetyCenterUiDataTest { Bundle().apply { putStringArrayList( nonMatchingDismissedIssue.id, - arrayListOf(NON_MATCHING_GROUP_ID) + arrayListOf(NON_MATCHING_GROUP_ID), ) } - ) + ), ) - val result = - SafetyCenterUiData(safetyCenterData).getMatchingDismissedIssues(MATCHING_GROUP_ID) + val result = uiData(safetyCenterData).getMatchingDismissedIssues(MATCHING_GROUP_ID) assertThat(result).containsExactly(defaultMatchingDismissedIssue) } @Test fun getMatchingDismissedIssues_mappingMatchingDismissedIssue_returnsListOfDismissedIssues() { - val mappingMatchingDismissedIssue = createSafetyCenterIssue("id1", NON_MATCHING_GROUP_ID) - val nonMatchingDismissedIssue = createSafetyCenterIssue("id2", NON_MATCHING_GROUP_ID) + val mappingMatchingDismissedIssue = issue("id1", NON_MATCHING_GROUP_ID) + val nonMatchingDismissedIssue = issue("id2", NON_MATCHING_GROUP_ID) val safetyCenterData = createSafetyCenterData( dismissedIssues = listOf(mappingMatchingDismissedIssue, nonMatchingDismissedIssue), @@ -184,30 +189,28 @@ class SafetyCenterUiDataTest { Bundle().apply { putStringArrayList( mappingMatchingDismissedIssue.id, - arrayListOf(MATCHING_GROUP_ID) + arrayListOf(MATCHING_GROUP_ID), ) } - ) + ), ) - val result = - SafetyCenterUiData(safetyCenterData).getMatchingDismissedIssues(MATCHING_GROUP_ID) + val result = uiData(safetyCenterData).getMatchingDismissedIssues(MATCHING_GROUP_ID) assertThat(result).containsExactly(mappingMatchingDismissedIssue) } @Test fun getMatchingDismissedIssues_noDefaultMatchingDismissedIssue_returnsEmptyList() { - val nonMatchingDismissedIssue = createSafetyCenterIssue("id1", NON_MATCHING_GROUP_ID) - val nonDismissedIssue = createSafetyCenterIssue("id2", MATCHING_GROUP_ID) + val nonMatchingDismissedIssue = issue("id1", NON_MATCHING_GROUP_ID) + val nonDismissedIssue = issue("id2", MATCHING_GROUP_ID) val safetyCenterData = createSafetyCenterData( issues = listOf(nonDismissedIssue), - dismissedIssues = listOf(nonMatchingDismissedIssue) + dismissedIssues = listOf(nonMatchingDismissedIssue), ) - val result = - SafetyCenterUiData(safetyCenterData).getMatchingDismissedIssues(MATCHING_GROUP_ID) + val result = uiData(safetyCenterData).getMatchingDismissedIssues(MATCHING_GROUP_ID) assertThat(result).isEmpty() } @@ -215,24 +218,12 @@ class SafetyCenterUiDataTest { @Test fun getMatchingDismissedIssues_doesntReturnGreenIssues() { val greenDismissedIssue = - createSafetyCenterIssue( - "id1", - MATCHING_GROUP_ID, - severityLevel = ISSUE_SEVERITY_LEVEL_OK - ) + issue("id1", MATCHING_GROUP_ID, severityLevel = ISSUE_SEVERITY_LEVEL_OK) val yellowDismissedIssue = - createSafetyCenterIssue( - "id2", - MATCHING_GROUP_ID, - severityLevel = ISSUE_SEVERITY_LEVEL_RECOMMENDATION - ) + issue("id2", MATCHING_GROUP_ID, severityLevel = ISSUE_SEVERITY_LEVEL_RECOMMENDATION) val redDismissedIssue = - createSafetyCenterIssue( - "id3", - MATCHING_GROUP_ID, - severityLevel = ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING - ) - val nonMatchingDismissedIssue = createSafetyCenterIssue("id4", NON_MATCHING_GROUP_ID) + issue("id3", MATCHING_GROUP_ID, severityLevel = ISSUE_SEVERITY_LEVEL_CRITICAL_WARNING) + val nonMatchingDismissedIssue = issue("id4", NON_MATCHING_GROUP_ID) val safetyCenterData = createSafetyCenterData( dismissedIssues = @@ -240,25 +231,82 @@ class SafetyCenterUiDataTest { redDismissedIssue, yellowDismissedIssue, greenDismissedIssue, - nonMatchingDismissedIssue - ), + nonMatchingDismissedIssue, + ) ) - val result = - SafetyCenterUiData(safetyCenterData).getMatchingDismissedIssues(MATCHING_GROUP_ID) + val result = uiData(safetyCenterData).getMatchingDismissedIssues(MATCHING_GROUP_ID) assertThat(result).containsExactly(redDismissedIssue, yellowDismissedIssue).inOrder() } + @Test + fun issueUiDatas_returnsIssueUiData() { + val issue1 = issue("id1", "group1") + val issue2 = issue("id2", "group2") + val safetyCenterData = createSafetyCenterData(listOf(issue1, issue2)) + + val result = uiData(safetyCenterData).issueUiDatas + + assertThat(result) + .containsExactly( + IssueUiData(issue1, isDismissed = false), + IssueUiData(issue2, isDismissed = false), + ) + .inOrder() + } + + @Test + fun issueUiDatas_withResolvedIssues_returnsExpectedIssueUiData() { + val resolvedActionId = "actionId" + val resolvedIssue = issue("resolvedId", "group1") + val unresolvedIssue = issue("unresolvedId", "group2") + val safetyCenterData = createSafetyCenterData(listOf(resolvedIssue, unresolvedIssue)) + + val result = + uiData(safetyCenterData, resolvedIssues = mapOf(resolvedIssue.id to resolvedActionId)) + .issueUiDatas + + assertThat(result[0].resolvedIssueActionId).isEqualTo(resolvedActionId) + assertThat(result[1].resolvedIssueActionId).isNull() + } + + @Test + fun issueUiDatas_withSameTaskSourceId_returnsExpectedIssueUiData() { + val taskId = 42 + val sameTaskSourceId = "sameTaskSourceId" + val sameTaskIssue = + issueWithEncodedId( + encodeIssueId("sameTaskIssue", sourceId = sameTaskSourceId), + "group1", + ) + val differentTaskIssue = issue("differentTaskIssue", "group2") + val safetyCenterData = createSafetyCenterData(listOf(sameTaskIssue, differentTaskIssue)) + + val result = + uiData(safetyCenterData, taskId, sameTaskSourceIds = listOf(sameTaskSourceId)) + .issueUiDatas + + assertThat(result[0].launchTaskId).isEqualTo(taskId) + assertThat(result[1].launchTaskId).isNull() + } + private companion object { const val MATCHING_GROUP_ID = "matching_group_id" const val NON_MATCHING_GROUP_ID = "non_matching_group_id" + private fun uiData( + safetyCenterData: SafetyCenterData, + taskId: Int = 0, + sameTaskSourceIds: List<String> = emptyList(), + resolvedIssues: Map<IssueId, ActionId> = emptyMap(), + ) = SafetyCenterUiData(safetyCenterData, taskId, sameTaskSourceIds, resolvedIssues) + fun createSafetyCenterData( issues: List<SafetyCenterIssue> = listOf(), entryGroups: List<SafetyCenterEntryGroup> = listOf(), dismissedIssues: List<SafetyCenterIssue> = listOf(), - extras: Bundle = Bundle() + extras: Bundle = Bundle(), ): SafetyCenterData { val safetyCenterStatus = SafetyCenterStatus.Builder("status title", "status summary").build() @@ -276,20 +324,44 @@ class SafetyCenterUiDataTest { return builder.build() } - fun createSafetyCenterEntryGroup(groupId: String) = + fun createSafetyCenterExtras(issuesToGroupsMapping: Bundle) = + Bundle().apply { putBundle(ISSUES_TO_GROUPS_BUNDLE_KEY, issuesToGroupsMapping) } + + fun entryGroup(groupId: String) = SafetyCenterEntryGroup.Builder(groupId, "group title").build() - fun createSafetyCenterIssue( + fun issue( issueId: String, groupId: String, - severityLevel: Int = ISSUE_SEVERITY_LEVEL_RECOMMENDATION + severityLevel: Int = ISSUE_SEVERITY_LEVEL_RECOMMENDATION, + ): SafetyCenterIssue = issueWithEncodedId(encodeIssueId(issueId), groupId, severityLevel) + + private fun issueWithEncodedId( + encodedIssueId: String, + groupId: String, + severityLevel: Int = ISSUE_SEVERITY_LEVEL_RECOMMENDATION, ) = - SafetyCenterIssue.Builder(issueId, "issue title", "issue summary") + SafetyCenterIssue.Builder(encodedIssueId, "issue title", "issue summary") .setSeverityLevel(severityLevel) .setGroupId(groupId) .build() - fun createSafetyCenterExtras(issuesToGroupsMapping: Bundle) = - Bundle().apply { putBundle(ISSUES_TO_GROUPS_BUNDLE_KEY, issuesToGroupsMapping) } + fun encodeIssueId( + sourceIssueId: String, + sourceId: String = "defaultSource", + issueTypeId: String = "defaultIssueTypeId", + ): String = + SafetyCenterIds.encodeToString( + SafetyCenterIssueId.newBuilder() + .setSafetyCenterIssueKey( + SafetyCenterIssueKey.newBuilder() + .setSafetySourceId(sourceId) + .setSafetySourceIssueId(sourceIssueId) + .setUserId(UserHandle.myUserId()) + .build() + ) + .setIssueTypeId(issueTypeId) + .build() + ) } } diff --git a/SafetyCenter/OWNERS b/SafetyCenter/OWNERS index d9039e915..229331d3c 100644 --- a/SafetyCenter/OWNERS +++ b/SafetyCenter/OWNERS @@ -4,7 +4,6 @@ simonjw@google.com davidcoffin@google.com elliotsisteron@google.com fiscella@google.com -shrigupt@google.com jtomljanovic@google.com deweytyl@google.com maxspencer@google.com diff --git a/SafetyCenter/Resources/res/values-mk-v35/strings.xml b/SafetyCenter/Resources/res/values-mk-v35/strings.xml index c4fc4bd17..1201ae74f 100644 --- a/SafetyCenter/Resources/res/values-mk-v35/strings.xml +++ b/SafetyCenter/Resources/res/values-mk-v35/strings.xml @@ -21,7 +21,7 @@ <string name="cellular_network_security_summary" msgid="7319307247487475572">"Тип мрежа, шифрирање, контроли за известувања"</string> <string name="biometrics_title_for_private_profile" msgid="542819107383037820"></string> <string name="privacy_title" msgid="7047524783080782769">"Приватност"</string> - <string name="privacy_sources_title" msgid="309304028326660956">"Контроли на приватноста"</string> + <string name="privacy_sources_title" msgid="309304028326660956">"Контроли за приватност"</string> <string name="privacy_sources_summary" msgid="2165270848857537278">"Дозволи, контроли"</string> <string name="privacy_additional_title" msgid="4239060639056083649"></string> <string name="private_space_title" msgid="6158245041481535879">"Приватен простор"</string> diff --git a/SafetyCenter/Resources/res/values-mk/strings.xml b/SafetyCenter/Resources/res/values-mk/strings.xml index 2b2414d0d..379a5234b 100644 --- a/SafetyCenter/Resources/res/values-mk/strings.xml +++ b/SafetyCenter/Resources/res/values-mk/strings.xml @@ -33,9 +33,9 @@ <string name="permission_manager_title" msgid="5277347862821255015">"Управувач со дозволи"</string> <string name="permission_manager_summary" msgid="8099852107340970790">"Го контролира пристапот на апликациите до вашите податоци"</string> <string name="permission_manager_search_terms" msgid="2895147613099694722">"Дозволи, Управувач со дозволи"</string> - <string name="privacy_controls_title" msgid="5322875777945432395">"Контроли за приватноста"</string> + <string name="privacy_controls_title" msgid="5322875777945432395">"Контроли за приватност"</string> <string name="privacy_controls_summary" msgid="2402066941190435424">"Го контролира пристапот на уредот до микрофонот, камерата и друго"</string> - <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Приватност, Контроли на приватноста"</string> + <string name="privacy_controls_search_terms" msgid="3774472175934304165">"Приватност, Контроли за приватност"</string> <string name="advanced_title" msgid="8745436380690561172">"Повеќе поставки"</string> <string name="advanced_security_title" msgid="1126833338772188155">"Повеќе поставки за безбедност"</string> <string name="advanced_security_summary" msgid="6172253327022425123">"Шифрирање, акредитиви и друго"</string> diff --git a/service/java/com/android/permission/util/UserUtils.java b/service/java/com/android/permission/util/UserUtils.java index 82e9cbbae..ae8e794b6 100644 --- a/service/java/com/android/permission/util/UserUtils.java +++ b/service/java/com/android/permission/util/UserUtils.java @@ -70,8 +70,7 @@ public final class UserUtils { return; } - Context userContext = UserUtils.getUserContext(userId, context); - List<UserHandle> profiles = getUserProfiles(userContext, true); + List<UserHandle> profiles = getUserProfiles(userId, context, true); final int profilesSize = profiles.size(); for (int i = 0; i < profilesSize; i++) { int profileId = profiles.get(i).getIdentifier(); @@ -112,26 +111,29 @@ public final class UserUtils { } } - /** Returns all the enabled user profiles on the device. */ + /** Returns all the enabled user profiles on the device for a specified user. */ @NonNull - public static List<UserHandle> getUserProfiles(@NonNull Context context) { - return getUserProfiles(context, false); + public static List<UserHandle> getUserProfiles(@UserIdInt int userId, + @NonNull Context context) { + return getUserProfiles(userId, context, false); } /** - * Returns all the enabled user profiles on the device + * Returns all the enabled user profiles on the device for a specified user * + * @param userId the user id to check * @param context the {@link Context} * @param excludePrivate {@code true} to exclude private profiles from returned list of users */ @NonNull - public static List<UserHandle> getUserProfiles(@NonNull Context context, + public static List<UserHandle> getUserProfiles(@UserIdInt int userId, @NonNull Context context, boolean excludePrivate) { - UserManager userManager = context.getSystemService(UserManager.class); // This call requires the QUERY_USERS permission. final long identity = Binder.clearCallingIdentity(); try { - List<UserHandle> profiles = userManager.getUserProfiles(); + Context userContext = getUserContext(userId, context); + UserManager userUserManager = userContext.getSystemService(UserManager.class); + List<UserHandle> profiles = userUserManager.getUserProfiles(); if (!excludePrivate) { return profiles; } @@ -139,7 +141,7 @@ public final class UserUtils { final int profilesSize = profiles.size(); for (int i = 0; i < profilesSize; i++) { UserHandle user = profiles.get(i); - if (!isPrivateProfile(user.getIdentifier(), context)) { + if (!isPrivateProfile(user.getIdentifier(), userContext)) { filteredProfiles.add(user); } } @@ -164,11 +166,11 @@ public final class UserUtils { @Nullable private static UserHandle getProfileParent(@UserIdInt int userId, @NonNull Context context) { Context userContext = getUserContext(userId, context); - UserManager userManager = userContext.getSystemService(UserManager.class); + UserManager userUserManager = userContext.getSystemService(UserManager.class); // This call requires the INTERACT_ACROSS_USERS permission. final long identity = Binder.clearCallingIdentity(); try { - return userManager.getProfileParent(UserHandle.of(userId)); + return userUserManager.getProfileParent(UserHandle.of(userId)); } finally { Binder.restoreCallingIdentity(identity); } @@ -201,8 +203,8 @@ public final class UserUtils { final long identity = Binder.clearCallingIdentity(); try { Context userContext = getUserContext(userId, context); - UserManager userManager = userContext.getSystemService(UserManager.class); - return userManager != null && userManager.isPrivateProfile(); + UserManager userUserManager = userContext.getSystemService(UserManager.class); + return userUserManager != null && userUserManager.isPrivateProfile(); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/service/java/com/android/role/RoleService.java b/service/java/com/android/role/RoleService.java index 5bc79efbb..e5d20ef9d 100644 --- a/service/java/com/android/role/RoleService.java +++ b/service/java/com/android/role/RoleService.java @@ -564,8 +564,7 @@ public class RoleService extends SystemService implements RoleUserState.Callback + " for role"); return; } - Context userContext = UserUtils.getUserContext(userId, getContext()); - List<UserHandle> profiles = UserUtils.getUserProfiles(userContext, true); + List<UserHandle> profiles = UserUtils.getUserProfiles(userId, getContext(), true); if (!profiles.contains(UserHandle.of(activeUserId))) { Log.e(LOG_TAG, "User " + activeUserId + " is not in the same profile-group as " + userId); diff --git a/service/java/com/android/safetycenter/UserProfileGroup.java b/service/java/com/android/safetycenter/UserProfileGroup.java index 1f5258437..44cb8d3d6 100644 --- a/service/java/com/android/safetycenter/UserProfileGroup.java +++ b/service/java/com/android/safetycenter/UserProfileGroup.java @@ -129,9 +129,8 @@ public final class UserProfileGroup { * is disabled. */ public static UserProfileGroup fromUser(Context context, @UserIdInt int userId) { - Context userContext = UserUtils.getUserContext(userId, context); - List<UserHandle> userProfiles = UserUtils.getUserProfiles(userContext); - int profileParentUserId = UserUtils.getProfileParentIdOrSelf(userId, userContext); + List<UserHandle> userProfiles = UserUtils.getUserProfiles(userId, context); + int profileParentUserId = UserUtils.getProfileParentIdOrSelf(userId, context); int[] managedProfilesUserIds = new int[userProfiles.size()]; int[] managedRunningProfilesUserIds = new int[userProfiles.size()]; diff --git a/tests/cts/permission/src/android/permission/cts/DevicePermissionsTest.kt b/tests/cts/permission/src/android/permission/cts/DevicePermissionsTest.kt index ff333c6a0..145936382 100644 --- a/tests/cts/permission/src/android/permission/cts/DevicePermissionsTest.kt +++ b/tests/cts/permission/src/android/permission/cts/DevicePermissionsTest.kt @@ -22,6 +22,10 @@ import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_S import android.app.Instrumentation import android.companion.virtual.VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT import android.companion.virtual.VirtualDeviceManager.VirtualDevice +import android.companion.virtual.VirtualDeviceParams +import android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM +import android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT +import android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO import android.content.Context import android.content.Intent import android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME @@ -33,10 +37,7 @@ import android.content.pm.PackageManager.PERMISSION_GRANTED import android.os.Build import android.os.UserHandle import android.permission.PermissionManager -import android.permission.flags.Flags import android.platform.test.annotations.AppModeFull -import android.platform.test.annotations.RequiresFlagsDisabled -import android.platform.test.annotations.RequiresFlagsEnabled import android.platform.test.flag.junit.DeviceFlagsValueProvider import android.virtualdevice.cts.common.VirtualDeviceRule import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -66,18 +67,25 @@ class DevicePermissionsTest { private lateinit var permissionManager: PermissionManager @get:Rule - var mVirtualDeviceRule = VirtualDeviceRule.withAdditionalPermissions( + var mVirtualDeviceRule = + VirtualDeviceRule.withAdditionalPermissions( Manifest.permission.GRANT_RUNTIME_PERMISSIONS, Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS, Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, - Manifest.permission.GET_RUNTIME_PERMISSIONS + Manifest.permission.GET_RUNTIME_PERMISSIONS, ) @Rule @JvmField val mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() @Before fun setup() { - virtualDevice = mVirtualDeviceRule.createManagedVirtualDevice() + virtualDevice = + mVirtualDeviceRule.createManagedVirtualDevice( + // Without custom audio policy, the RECORD_AUDIO permission won't be device aware. + VirtualDeviceParams.Builder() + .setDevicePolicy(POLICY_TYPE_AUDIO, DEVICE_POLICY_CUSTOM) + .build() + ) virtualDeviceContext = defaultDeviceContext.createDeviceContext(virtualDevice.deviceId) permissionManager = virtualDeviceContext.getSystemService(PermissionManager::class.java)!! persistentDeviceId = virtualDevice.persistentDeviceId!! @@ -89,43 +97,47 @@ class DevicePermissionsTest { runShellCommandOrThrow("pm uninstall $TEST_PACKAGE_NAME") } - @RequiresFlagsEnabled( - Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED, - Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED - ) @Test - fun testDeviceAwareRuntimePermissionIsGranted() { - grantPermissionAndAssertGranted(Manifest.permission.CAMERA, virtualDeviceContext) + fun virtualDeviceDefaultPolicy_deviceAwarePermissionFallsBackToDefaultDevice() { + virtualDevice = + mVirtualDeviceRule.createManagedVirtualDevice( + // With default audio policy, the RECORD_AUDIO permission won't be device aware. + VirtualDeviceParams.Builder() + .setDevicePolicy(POLICY_TYPE_AUDIO, DEVICE_POLICY_DEFAULT) + .build() + ) + virtualDeviceContext = defaultDeviceContext.createDeviceContext(virtualDevice.deviceId) + + grantPermissionAndAssertGranted(DEVICE_AWARE_PERMISSION, defaultDeviceContext) + assertPermission(DEVICE_AWARE_PERMISSION, PERMISSION_GRANTED, virtualDeviceContext) } - @RequiresFlagsDisabled(Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED) @Test - fun testDeviceAwareRuntimePermissionGrantIsInherited() { - grantPermissionAndAssertGranted(Manifest.permission.CAMERA, defaultDeviceContext) + fun virtualDeviceCustomPolicy_deviceAwarePermissionGrantedOnVirtualDevice() { + // When a device aware permission is granted on the default device, it's not automatically + // granted on the virtual device. + grantPermissionAndAssertGranted(DEVICE_AWARE_PERMISSION, defaultDeviceContext) + assertPermission(DEVICE_AWARE_PERMISSION, PERMISSION_DENIED, virtualDeviceContext) - assertPermission(Manifest.permission.CAMERA, PERMISSION_GRANTED, virtualDeviceContext) + grantPermissionAndAssertGranted(DEVICE_AWARE_PERMISSION, virtualDeviceContext) } @Test - fun testNonDeviceAwareRuntimePermissionGrantIsInherited() { + fun normalPermissionGrantedOnDefaultDevice_isGrantedOnVirtualDevice() { grantPermissionAndAssertGranted(NON_DEVICE_AWARE_PERMISSION, defaultDeviceContext) assertPermission(NON_DEVICE_AWARE_PERMISSION, PERMISSION_GRANTED, virtualDeviceContext) } - @RequiresFlagsEnabled( - Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED, - Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED - ) @Test - fun testDeviceAwareRuntimePermissionIsRevoked() { + fun virtualDeviceCustomPolicy_deviceAwarePermissionIsRevoked() { grantPermissionAndAssertGranted(DEVICE_AWARE_PERMISSION, virtualDeviceContext) revokePermissionAndAssertDenied(DEVICE_AWARE_PERMISSION, virtualDeviceContext) } @Test - fun testNonDeviceAwareRuntimePermissionIsRevokedForDefaultDevice() { + fun normalPermissionRevokedFromVirtualDevice_isAlsoRevokedOnDefaultDevice() { grantPermissionAndAssertGranted(NON_DEVICE_AWARE_PERMISSION, defaultDeviceContext) assertPermission(NON_DEVICE_AWARE_PERMISSION, PERMISSION_GRANTED, virtualDeviceContext) // Revoke call from virtualDeviceContext should revoke for default device as well. @@ -134,24 +146,24 @@ class DevicePermissionsTest { } @Test - fun testNormalPermissionGrantIsInherited() { + fun normalPermission_isInheritedOnVirtualDevice() { assertPermission(Manifest.permission.INTERNET, PERMISSION_GRANTED, virtualDeviceContext) } @Test - fun testSignaturePermissionGrantIsInherited() { + fun signaturePermission_isInheritedOnVirtualDevice() { assertPermission(CUSTOM_SIGNATURE_PERMISSION, PERMISSION_GRANTED, virtualDeviceContext) } @Test - fun testOneTimePermissionIsRevoked() { + fun virtualDeviceCustomPolicy_oneTimePermissionIsRevoked() { grantPermissionAndAssertGranted(DEVICE_AWARE_PERMISSION, virtualDeviceContext) virtualDeviceContext.packageManager.updatePermissionFlags( DEVICE_AWARE_PERMISSION, TEST_PACKAGE_NAME, FLAG_PERMISSION_ONE_TIME, FLAG_PERMISSION_ONE_TIME, - UserHandle.of(virtualDeviceContext.userId) + UserHandle.of(virtualDeviceContext.userId), ) permissionManager.startOneTimePermissionSession( @@ -159,19 +171,15 @@ class DevicePermissionsTest { 0, 0, IMPORTANCE_FOREGROUND, - IMPORTANCE_FOREGROUND_SERVICE + IMPORTANCE_FOREGROUND_SERVICE, ) eventually { assertPermission(DEVICE_AWARE_PERMISSION, PERMISSION_DENIED, virtualDeviceContext) } } - @RequiresFlagsEnabled( - Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED, - Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED - ) @Test - fun testRevokeSelfPermissionOnKill() { + fun virtualDeviceCustomPolicy_revokeSelfPermissionOnKill_permissionIsRevoked() { grantPermissionAndAssertGranted(DEVICE_AWARE_PERMISSION, virtualDeviceContext) revokeSelfPermission(DEVICE_AWARE_PERMISSION, virtualDeviceContext) @@ -180,105 +188,90 @@ class DevicePermissionsTest { } } - @RequiresFlagsEnabled( - Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED, - Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED - ) @Test - fun testGrantAndRevokeDeviceAwarePermissionByPersistentDeviceId() { - val deviceAwarePermission = DEVICE_AWARE_PERMISSION - + fun usePersistentDeviceIdToRevokeDeviceAwarePermission_permissionIsRevoked() { permissionManager.grantRuntimePermission( TEST_PACKAGE_NAME, - deviceAwarePermission, - persistentDeviceId + DEVICE_AWARE_PERMISSION, + persistentDeviceId, ) assertThat( permissionManager.checkPermission( - deviceAwarePermission, + DEVICE_AWARE_PERMISSION, TEST_PACKAGE_NAME, - virtualDevice.persistentDeviceId!! + virtualDevice.persistentDeviceId!!, ) ) .isEqualTo(PERMISSION_GRANTED) assertThat( permissionManager.checkPermission( - deviceAwarePermission, + DEVICE_AWARE_PERMISSION, TEST_PACKAGE_NAME, - PERSISTENT_DEVICE_ID_DEFAULT + PERSISTENT_DEVICE_ID_DEFAULT, ) ) .isEqualTo(PERMISSION_DENIED) permissionManager.revokeRuntimePermission( TEST_PACKAGE_NAME, - deviceAwarePermission, + DEVICE_AWARE_PERMISSION, persistentDeviceId, - "test" + "test", ) assertThat( permissionManager.checkPermission( - deviceAwarePermission, + DEVICE_AWARE_PERMISSION, TEST_PACKAGE_NAME, - virtualDevice.persistentDeviceId!! + virtualDevice.persistentDeviceId!!, ) ) .isEqualTo(PERMISSION_DENIED) } - @RequiresFlagsEnabled( - Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED, - Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED - ) @Test - fun testUpdateAndGetPermissionFlagsByPersistentDeviceId() { - val deviceAwarePermission = DEVICE_AWARE_PERMISSION + fun updateAndGetPermissionFlagsByPersistentDeviceId() { val flagMask = FLAG_PERMISSION_USER_SET or FLAG_PERMISSION_USER_FIXED val flag = FLAG_PERMISSION_USER_SET assertThat( permissionManager.getPermissionFlags( TEST_PACKAGE_NAME, - deviceAwarePermission, - persistentDeviceId + DEVICE_AWARE_PERMISSION, + persistentDeviceId, ) ) .isEqualTo(0) permissionManager.updatePermissionFlags( TEST_PACKAGE_NAME, - deviceAwarePermission, + DEVICE_AWARE_PERMISSION, persistentDeviceId, flagMask, - flag + flag, ) assertThat( permissionManager.getPermissionFlags( TEST_PACKAGE_NAME, - deviceAwarePermission, - persistentDeviceId + DEVICE_AWARE_PERMISSION, + persistentDeviceId, ) ) .isEqualTo(FLAG_PERMISSION_USER_SET) } - @RequiresFlagsEnabled( - Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED, - Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED - ) @Test - fun testAllPermissionStatesApiGrantForVirtualDevice() { + fun permissionGrantedOnVirtualDevice_reflectedInGetAllPermissionStatesApi() { // Setting a flag explicitly so that the permission consistently stays in the state permissionManager.updatePermissionFlags( TEST_PACKAGE_NAME, DEVICE_AWARE_PERMISSION, PERSISTENT_DEVICE_ID_DEFAULT, FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, - FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED + FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, ) assertThat( @@ -291,7 +284,7 @@ class DevicePermissionsTest { permissionManager.grantRuntimePermission( TEST_PACKAGE_NAME, DEVICE_AWARE_PERMISSION, - persistentDeviceId + persistentDeviceId, ) val permissionStateMap = @@ -312,7 +305,7 @@ class DevicePermissionsTest { TEST_PACKAGE_NAME, DEVICE_AWARE_PERMISSION, persistentDeviceId, - "test" + "test", ) assertThat( @@ -323,12 +316,8 @@ class DevicePermissionsTest { .isFalse() } - @RequiresFlagsEnabled( - Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED, - Flags.FLAG_DEVICE_AWARE_PERMISSIONS_ENABLED - ) @Test - fun testAllPermissionStatesApiFlagsForVirtualDevice() { + fun setPermissionFlagOnVirtualDevice_reflectedInGetAllPermissionStatesApi() { val flagMask = FLAG_PERMISSION_USER_SET or FLAG_PERMISSION_USER_FIXED val flag = FLAG_PERMISSION_USER_SET @@ -340,7 +329,7 @@ class DevicePermissionsTest { DEVICE_AWARE_PERMISSION, persistentDeviceId, flagMask, - flag + flag, ) assertThat( @@ -349,7 +338,7 @@ class DevicePermissionsTest { .getAllPermissionStates(TEST_PACKAGE_NAME, persistentDeviceId)[ DEVICE_AWARE_PERMISSION]!! .flags, - flag + flag, ) ) .isTrue() @@ -360,15 +349,14 @@ class DevicePermissionsTest { .getAllPermissionStates(TEST_PACKAGE_NAME, persistentDeviceId)[ DEVICE_AWARE_PERMISSION]!! .flags, - FLAG_PERMISSION_USER_FIXED + FLAG_PERMISSION_USER_FIXED, ) ) .isFalse() } - @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) @Test - fun testAllPermissionStatesApiGrantForDefaultDevice() { + fun permissionGrantedOnDefaultDevice_reflectedInGetAllPermissionStatesApi() { // Setting a flag explicitly so that the permission consistently stays in the state upon // revoke permissionManager.updatePermissionFlags( @@ -376,13 +364,13 @@ class DevicePermissionsTest { DEVICE_AWARE_PERMISSION, PERSISTENT_DEVICE_ID_DEFAULT, FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, - FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED + FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, ) permissionManager.grantRuntimePermission( TEST_PACKAGE_NAME, DEVICE_AWARE_PERMISSION, - PERSISTENT_DEVICE_ID_DEFAULT + PERSISTENT_DEVICE_ID_DEFAULT, ) assertThat( @@ -404,7 +392,7 @@ class DevicePermissionsTest { TEST_PACKAGE_NAME, DEVICE_AWARE_PERMISSION, PERSISTENT_DEVICE_ID_DEFAULT, - "test" + "test", ) assertThat( @@ -416,9 +404,8 @@ class DevicePermissionsTest { .isFalse() } - @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) @Test - fun testAllPermissionStatesApiFlagsForDefaultDevice() { + fun setPermissionFlagOnDefaultDevice_reflectedInGetAllPermissionStatesApi() { val flagMask = FLAG_PERMISSION_USER_SET or FLAG_PERMISSION_USER_FIXED val flag = FLAG_PERMISSION_USER_SET @@ -434,7 +421,7 @@ class DevicePermissionsTest { DEVICE_AWARE_PERMISSION, PERSISTENT_DEVICE_ID_DEFAULT, flagMask, - flag + flag, ) assertThat( @@ -443,7 +430,7 @@ class DevicePermissionsTest { .getAllPermissionStates(TEST_PACKAGE_NAME, PERSISTENT_DEVICE_ID_DEFAULT)[ DEVICE_AWARE_PERMISSION]!! .flags, - flag + flag, ) ) .isTrue() @@ -454,19 +441,18 @@ class DevicePermissionsTest { .getAllPermissionStates(TEST_PACKAGE_NAME, PERSISTENT_DEVICE_ID_DEFAULT)[ DEVICE_AWARE_PERMISSION]!! .flags, - FLAG_PERMISSION_USER_FIXED + FLAG_PERMISSION_USER_FIXED, ) ) .isFalse() } - @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) @Test - fun testAllPermissionStatesApiThatNonDeviceAwareRuntimePermissionGrantIsNotInherited() { + fun getAllPermissionStates_normalPermissionIsNotInherited() { permissionManager.grantRuntimePermission( TEST_PACKAGE_NAME, NON_DEVICE_AWARE_PERMISSION, - PERSISTENT_DEVICE_ID_DEFAULT + PERSISTENT_DEVICE_ID_DEFAULT, ) assertThat( @@ -501,7 +487,7 @@ class DevicePermissionsTest { context.packageManager.grantRuntimePermission( TEST_PACKAGE_NAME, permissionName, - UserHandle.of(context.userId) + UserHandle.of(context.userId), ) assertPermission(permissionName, PERMISSION_GRANTED, context) } @@ -510,18 +496,14 @@ class DevicePermissionsTest { context.packageManager.revokeRuntimePermission( TEST_PACKAGE_NAME, permissionName, - UserHandle.of(context.userId) + UserHandle.of(context.userId), ) assertPermission(permissionName, PERMISSION_DENIED, context) } - private fun assertPermission( - permissionName: String, - permissionState: Int, - context: Context, - ) { - assertThat(context.packageManager.checkPermission(permissionName, TEST_PACKAGE_NAME)) - .isEqualTo(permissionState) + private fun assertPermission(permissionName: String, permissionState: Int, context: Context) { + val uid = defaultDeviceContext.packageManager.getApplicationInfo(TEST_PACKAGE_NAME, 0).uid + assertThat(context.checkPermission(permissionName, -1, uid)).isEqualTo(permissionState) } companion object { diff --git a/tests/cts/permissionpolicy/res/raw/android_manifest.xml b/tests/cts/permissionpolicy/res/raw/android_manifest.xml index 9ad619596..2547b9786 100644 --- a/tests/cts/permissionpolicy/res/raw/android_manifest.xml +++ b/tests/cts/permissionpolicy/res/raw/android_manifest.xml @@ -7759,7 +7759,17 @@ @FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies") @hide --> <permission android:name="android.permission.READ_BLOCKED_NUMBERS" - android:protectionLevel="signature" /> + android:protectionLevel="signature" + android:featureFlag="!android.permission.flags.grant_read_blocked_numbers_to_system_ui_intelligence" /> + + <!-- Allows the holder to read blocked numbers. See + {@link android.provider.BlockedNumberContract}. + @SystemApi + @FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies") + @hide --> + <permission android:name="android.permission.READ_BLOCKED_NUMBERS" + android:protectionLevel="signature|role" + android:featureFlag="android.permission.flags.grant_read_blocked_numbers_to_system_ui_intelligence" /> <!-- Allows the holder to write blocked numbers. See {@link android.provider.BlockedNumberContract}. diff --git a/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt index ccc5a0a5e..f52e32344 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt @@ -38,6 +38,7 @@ import android.provider.DeviceConfig import android.provider.Settings import android.text.Spanned import android.text.style.ClickableSpan +import android.util.Log import android.view.View import android.view.accessibility.AccessibilityNodeInfo import androidx.test.uiautomator.By @@ -51,6 +52,7 @@ import com.android.compatibility.common.util.SystemUtil import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity import com.android.compatibility.common.util.SystemUtil.eventually import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity +import com.android.compatibility.common.util.UiDumpUtils import com.android.modules.utils.build.SdkLevel import java.util.concurrent.CompletableFuture import java.util.concurrent.TimeUnit @@ -64,6 +66,7 @@ import org.junit.Before abstract class BaseUsePermissionTest : BasePermissionTest() { companion object { + const val LOG_TAG = "BaseUsePermissionTest" const val APP_APK_NAME_31 = "CtsUsePermissionApp31.apk" const val APP_APK_NAME_31_WITH_ASL = "CtsUsePermissionApp31WithAsl.apk" const val APP_APK_NAME_LATEST = "CtsUsePermissionAppLatest.apk" @@ -791,6 +794,9 @@ abstract class BaseUsePermissionTest : BasePermissionTest() { ) if (timeoutOccurred) { + val uiDump = StringBuilder() + UiDumpUtils.dumpNodes(uiDump) + Log.w(LOG_TAG, "Timed out waiting for window transition, UI dump: $uiDump") throw RuntimeException("Timed out waiting for window transition.") } } diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionDecisionsTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionDecisionsTest.kt index ae6e33b2a..e4ee52186 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/PermissionDecisionsTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionDecisionsTest.kt @@ -53,7 +53,8 @@ class PermissionDecisionsTest : BaseUsePermissionTest() { openPermissionDecisions() waitFindObject( By.hasChild( - By.text("You gave $APP_PACKAGE_NAME access to location").displayId(displayId)) + By.text("You gave $APP_PACKAGE_NAME access to location").displayId(displayId) + ) .hasChild(By.text("Today").displayId(displayId)) .displayId(displayId) ) @@ -69,7 +70,8 @@ class PermissionDecisionsTest : BaseUsePermissionTest() { openPermissionDecisions() waitFindObject( By.hasChild( - By.text("You denied $APP_PACKAGE_NAME access to location").displayId(displayId)) + By.text("You denied $APP_PACKAGE_NAME access to location").displayId(displayId) + ) .hasChild(By.text("Today").displayId(displayId)) .displayId(displayId) ) @@ -86,11 +88,13 @@ class PermissionDecisionsTest : BaseUsePermissionTest() { openPermissionDecisions() assertNull( waitFindObjectOrNull( - By.hasChild(By.text("You denied $APP_PACKAGE_NAME access to location") - .displayId(displayId)) + By.hasChild( + By.text("You denied $APP_PACKAGE_NAME access to location") + .displayId(displayId) + ) .hasChild(By.text("Today").displayId(displayId)) .displayId(displayId), - ASSERT_ABSENT_SELECTOR_TIMEOUT_MS + ASSERT_ABSENT_SELECTOR_TIMEOUT_MS, ) ) } @@ -105,8 +109,10 @@ class PermissionDecisionsTest : BaseUsePermissionTest() { openPermissionDecisions() waitFindObject( - By.hasChild(By.text("You gave $APP_PACKAGE_NAME access to location") - .displayId(displayId)) + By.hasChild( + By.text("You gave $APP_PACKAGE_NAME access to location") + .displayId(displayId) + ) .hasChild(By.text("Today").displayId(displayId)) .displayId(displayId) ) @@ -121,7 +127,8 @@ class PermissionDecisionsTest : BaseUsePermissionTest() { pressBack() waitFindObject( By.hasChild( - By.text("You denied $APP_PACKAGE_NAME access to location").displayId(displayId)) + By.text("You denied $APP_PACKAGE_NAME access to location").displayId(displayId) + ) .hasChild(By.text("Today").displayId(displayId)) .displayId(displayId) ) @@ -132,7 +139,7 @@ class PermissionDecisionsTest : BaseUsePermissionTest() { SystemUtil.runWithShellPermissionIdentity { context.startActivity( Intent(PermissionManager.ACTION_REVIEW_PERMISSION_DECISIONS).apply { - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) } ) } diff --git a/tests/cts/permissionui/src/android/permissionui/cts/PermissionSplitTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/PermissionSplitTest.kt index c2b5447dd..17cef0e31 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/PermissionSplitTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/PermissionSplitTest.kt @@ -16,6 +16,7 @@ package android.permissionui.cts +import android.content.pm.PackageManager import android.health.connect.HealthPermissions import android.os.Build import android.permission.flags.Flags.FLAG_REPLACE_BODY_SENSOR_PERMISSION_ENABLED @@ -25,6 +26,7 @@ import android.platform.test.flag.junit.DeviceFlagsValueProvider import androidx.test.filters.FlakyTest import androidx.test.filters.SdkSuppress import org.junit.Assume.assumeFalse +import org.junit.Assume.assumeTrue import org.junit.Before import org.junit.Rule import org.junit.Test @@ -33,6 +35,12 @@ import org.junit.Test @FlakyTest class PermissionSplitTest : BaseUsePermissionTest() { + companion object { + @JvmStatic + private val supportHeartrate = + packageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_HEART_RATE) + } + @Rule @JvmField val mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() @Before @@ -146,6 +154,7 @@ class PermissionSplitTest : BaseUsePermissionTest() { @RequiresFlagsEnabled(FLAG_REPLACE_BODY_SENSOR_PERMISSION_ENABLED) @Test fun testBodySensorSplitOnBaklava_splitToReadHeartRate() { + assumeTrue(supportHeartrate) installPackage(APP_APK_PATH_30_WITH_BACKGROUND) assertAppHasPermission(android.Manifest.permission.BODY_SENSORS, false) assertAppHasPermission(HealthPermissions.READ_HEART_RATE, false) @@ -195,6 +204,7 @@ class PermissionSplitTest : BaseUsePermissionTest() { } private fun testBodySensorPermissionSplitToBodySensorsBackground(expectSplit: Boolean) { + assumeTrue(supportHeartrate) assertAppHasPermission(android.Manifest.permission.BODY_SENSORS, false) assertAppHasPermission(android.Manifest.permission.BODY_SENSORS_BACKGROUND, false) diff --git a/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt b/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt index 98aa5fbf1..3e24d5025 100644 --- a/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt +++ b/tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt @@ -27,10 +27,12 @@ import android.os.Process import android.os.UserHandle import android.os.UserManager.DISALLOW_CONFIG_DEFAULT_APPS import android.provider.Settings +import android.util.Log import android.util.Pair import androidx.test.filters.SdkSuppress import androidx.test.rule.ActivityTestRule import androidx.test.uiautomator.By +import com.android.bedstead.enterprise.annotations.EnsureDoesNotHaveUserRestriction import com.android.bedstead.enterprise.annotations.EnsureHasNoWorkProfile import com.android.bedstead.enterprise.annotations.EnsureHasUserRestriction import com.android.bedstead.enterprise.annotations.EnsureHasWorkProfile @@ -53,6 +55,7 @@ import com.android.bedstead.nene.TestApis.context import com.android.bedstead.nene.TestApis.permissions import com.android.bedstead.nene.TestApis.users import com.android.bedstead.nene.types.OptionalBoolean +import com.android.bedstead.nene.userrestrictions.CommonUserRestrictions.DISALLOW_ADD_MANAGED_PROFILE import com.android.bedstead.nene.users.UserReference import com.android.bedstead.nene.users.UserType import com.android.bedstead.permissions.CommonPermissions.INTERACT_ACROSS_USERS_FULL @@ -69,7 +72,6 @@ import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObjectOrNull import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertWithMessage -import java.util.Objects import java.util.concurrent.CompletableFuture import java.util.concurrent.TimeUnit import java.util.function.Consumer @@ -94,16 +96,24 @@ class RoleManagerMultiUserTest { ActivityTestRule(WaitForResultActivity::class.java) @Before - @Throws(java.lang.Exception::class) fun setUp() { assumeTrue(RoleManagerUtil.isCddCompliantScreenSize()) installAppForAllUsers() + + // If "none" selected in test, ensure we re-enable fallback for other test runs + permissions().withPermission(MANAGE_ROLE_HOLDERS, INTERACT_ACROSS_USERS_FULL).use { + setRoleFallbackEnabledForAllUsers() + } } @After - @Throws(java.lang.Exception::class) fun tearDown() { uninstallAppForAllUsers() + + // If "none" selected in test, ensure we re-enable fallback for other test runs + permissions().withPermission(MANAGE_ROLE_HOLDERS, INTERACT_ACROSS_USERS_FULL).use { + setRoleFallbackEnabledForAllUsers() + } } @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) @@ -315,7 +325,7 @@ class RoleManagerMultiUserTest { // initialUser needs to be not the targetUser val targetActiveUser = users().current().userHandle() val initialUser = - if (Objects.equals(targetActiveUser, deviceState.initialUser().userHandle())) { + if (targetActiveUser == deviceState.initialUser().userHandle()) { deviceState.workProfile().userHandle() } else { deviceState.initialUser().userHandle() @@ -378,7 +388,7 @@ class RoleManagerMultiUserTest { val initialUser = deviceState.workProfile().userHandle() // setActiveUserForRole and getActiveUserForRole is used to ensure initial active users // state and requires INTERACT_ACROSS_USERS_FULL - permissions().withPermission(INTERACT_ACROSS_USERS_FULL).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL).use { roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, initialUser, 0) assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) .isEqualTo(initialUser) @@ -406,7 +416,7 @@ class RoleManagerMultiUserTest { // getActiveUserForRole is used to ensure addRoleHolderAsUser didn't set active user, and // requires INTERACT_ACROSS_USERS_FULL - permissions().withPermission(INTERACT_ACROSS_USERS_FULL).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL).use { assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) .isEqualTo(initialUser) } @@ -471,6 +481,47 @@ class RoleManagerMultiUserTest { assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) } + @RequireFlagsEnabled( + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED, + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_UX_BUGFIX_ENABLED, + ) + @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun addRoleHolderAsUserReenablesFallbackOnProfileParent() { + // Set other user as active + val initialUserReference = deviceState.initialUser() + val initialUser = initialUserReference.userHandle() + roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, initialUser, 0) + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(initialUser) + + val profileParentRoleManager = getRoleManagerForUser(initialUserReference) + profileParentRoleManager.setRoleFallbackEnabled(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, false) + assertThat( + profileParentRoleManager.isRoleFallbackEnabled(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + ) + .isFalse() + + val targetActiveUser = deviceState.workProfile().userHandle() + val future = CallbackFuture() + roleManager.addRoleHolderAsUser( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + targetActiveUser, + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + assertThat( + profileParentRoleManager.isRoleFallbackEnabled(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + ) + .isTrue() + } + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) @EnsureHasPermission(MANAGE_DEFAULT_APPLICATIONS) @EnsureDoesNotHavePermission(INTERACT_ACROSS_USERS_FULL) @@ -483,7 +534,7 @@ class RoleManagerMultiUserTest { val initialUser = deviceState.workProfile().userHandle() // setActiveUserForRole and getActiveUserForRole is used to ensure initial active users // state and requires INTERACT_ACROSS_USERS_FULL - permissions().withPermission(INTERACT_ACROSS_USERS_FULL).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL).use { roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, initialUser, 0) assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) .isEqualTo(initialUser) @@ -503,7 +554,7 @@ class RoleManagerMultiUserTest { // getActiveUserForRole is used to ensure setDefaultApplication didn't set active user, // and requires INTERACT_ACROSS_USERS_FULL - permissions().withPermission(INTERACT_ACROSS_USERS_FULL).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL).use { assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) .isEqualTo(initialUser) } @@ -565,11 +616,56 @@ class RoleManagerMultiUserTest { eventually { assertExpectedProfileHasRoleUsingGetDefaultApplication(targetActiveUser) } } + @RequireFlagsEnabled( + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED, + com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_UX_BUGFIX_ENABLED, + ) + @EnsureHasPermission( + INTERACT_ACROSS_USERS_FULL, + MANAGE_DEFAULT_APPLICATIONS, + MANAGE_ROLE_HOLDERS, + ) + @EnsureHasWorkProfile + @RequireRunOnPrimaryUser + @Test + @Throws(java.lang.Exception::class) + fun setDefaultApplicationReenablesFallbackOnProfileParent() { + // Set other user as active + val initialUserReference = deviceState.initialUser() + val initialUser = initialUserReference.userHandle() + roleManager.setActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, initialUser, 0) + assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) + .isEqualTo(initialUser) + + val profileParentRoleManager = getRoleManagerForUser(initialUserReference) + profileParentRoleManager.setRoleFallbackEnabled(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, false) + assertThat( + profileParentRoleManager.isRoleFallbackEnabled(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + ) + .isFalse() + + val future = CallbackFuture() + getRoleManagerForUser(deviceState.workProfile()) + .setDefaultApplication( + PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, + APP_PACKAGE_NAME, + 0, + context.mainExecutor, + future, + ) + assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue() + assertThat( + profileParentRoleManager.isRoleFallbackEnabled(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) + ) + .isTrue() + } + @RequireFlagsEnabled(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED) @EnsureHasPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS) @EnsureCanAddUser @EnsureHasNoWorkProfile @RequireRunOnPrimaryUser + @EnsureDoesNotHaveUserRestriction(DISALLOW_ADD_MANAGED_PROFILE) @Test @Throws(Exception::class) fun ensureActiveUserSetToParentOnUserRemoved() { @@ -1279,7 +1375,7 @@ class RoleManagerMultiUserTest { // setDefaultHoldersForTestForAllUsers and setRoleVisibleForTestForAllUsers require // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user // role active user and role holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { // Set test default role holder. Ensures fallbacks to a default holder setDefaultHoldersForTestForAllUsers() setRoleVisibleForTestForAllUsers() @@ -1306,7 +1402,7 @@ class RoleManagerMultiUserTest { // getActiveUserForRole and getRoleHoldersAsUser require INTERACT_ACROSS_USERS_FULL and // MANAGE_ROLE_HOLDERS permissions to validate cross user role active user and role // holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) .isEqualTo(targetActiveUser) assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) @@ -1315,7 +1411,7 @@ class RoleManagerMultiUserTest { // clearDefaultHoldersForTestForAllUsers and clearRoleVisibleForTestForAllUsers require // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user // role active user and role holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { clearDefaultHoldersForTestForAllUsers() clearRoleVisibleForTestForAllUsers() } @@ -1332,7 +1428,7 @@ class RoleManagerMultiUserTest { // setDefaultHoldersForTestForAllUsers and setRoleVisibleForTestForAllUsers require // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user // role active user and role holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { // Set test default role holder. Ensures fallbacks to a default holder setDefaultHoldersForTestForAllUsers() setRoleVisibleForTestForAllUsers() @@ -1359,7 +1455,7 @@ class RoleManagerMultiUserTest { // getActiveUserForRole and getRoleHoldersAsUser require INTERACT_ACROSS_USERS_FULL and // MANAGE_ROLE_HOLDERS permissions to validate cross user role active user and role // holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) .isEqualTo(targetActiveUser) assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) @@ -1368,7 +1464,7 @@ class RoleManagerMultiUserTest { // clearDefaultHoldersForTestForAllUsers and clearRoleVisibleForTestForAllUsers require // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user // role active user and role holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { clearDefaultHoldersForTestForAllUsers() clearRoleVisibleForTestForAllUsers() } @@ -1385,7 +1481,7 @@ class RoleManagerMultiUserTest { // setDefaultHoldersForTestForAllUsers and setRoleVisibleForTestForAllUsers require // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user // role active user and role holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { // Set test default role holder. Ensures fallbacks to a default holder setDefaultHoldersForTestForAllUsers() setRoleVisibleForTestForAllUsers() @@ -1410,7 +1506,7 @@ class RoleManagerMultiUserTest { // getActiveUserForRole and getRoleHoldersAsUser require INTERACT_ACROSS_USERS_FULL and // MANAGE_ROLE_HOLDERS permissions to validate cross user role active user and role // holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) .isEqualTo(deviceState.initialUser().userHandle()) assertNoRoleHoldersUsingGetRoleHoldersAsUser() @@ -1419,7 +1515,7 @@ class RoleManagerMultiUserTest { // clearDefaultHoldersForTestForAllUsers and clearRoleVisibleForTestForAllUsers require // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user // role active user and role holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { clearDefaultHoldersForTestForAllUsers() clearRoleVisibleForTestForAllUsers() } @@ -1436,7 +1532,7 @@ class RoleManagerMultiUserTest { // setDefaultHoldersForTestForAllUsers and setRoleVisibleForTestForAllUsers require // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user // role active user and role holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { // Set test default role holder. Ensures fallbacks to a default holder setDefaultHoldersForTestForAllUsers() setRoleVisibleForTestForAllUsers() @@ -1463,7 +1559,7 @@ class RoleManagerMultiUserTest { // getActiveUserForRole and getRoleHoldersAsUser require INTERACT_ACROSS_USERS_FULL and // MANAGE_ROLE_HOLDERS permissions to validate cross user role active user and role // holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) .isEqualTo(targetActiveUser) assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) @@ -1472,7 +1568,7 @@ class RoleManagerMultiUserTest { // clearDefaultHoldersForTestForAllUsers and clearRoleVisibleForTestForAllUsers require // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user // role active user and role holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { clearDefaultHoldersForTestForAllUsers() clearRoleVisibleForTestForAllUsers() } @@ -1489,7 +1585,7 @@ class RoleManagerMultiUserTest { // setDefaultHoldersForTestForAllUsers and setRoleVisibleForTestForAllUsers require // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user // role active user and role holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { // Set test default role holder. Ensures fallbacks to a default holder setDefaultHoldersForTestForAllUsers() setRoleVisibleForTestForAllUsers() @@ -1516,7 +1612,7 @@ class RoleManagerMultiUserTest { // getActiveUserForRole and getRoleHoldersAsUser require INTERACT_ACROSS_USERS_FULL and // MANAGE_ROLE_HOLDERS permissions to validate cross user role active user and role // holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) .isEqualTo(targetActiveUser) assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) @@ -1525,7 +1621,7 @@ class RoleManagerMultiUserTest { // clearDefaultHoldersForTestForAllUsers and clearRoleVisibleForTestForAllUsers require // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user // role active user and role holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { clearDefaultHoldersForTestForAllUsers() clearRoleVisibleForTestForAllUsers() } @@ -1542,7 +1638,7 @@ class RoleManagerMultiUserTest { // setDefaultHoldersForTestForAllUsers and setRoleVisibleForTestForAllUsers require // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user // role active user and role holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { // Set test default role holder. Ensures fallbacks to a default holder setDefaultHoldersForTestForAllUsers() setRoleVisibleForTestForAllUsers() @@ -1567,7 +1663,7 @@ class RoleManagerMultiUserTest { // getActiveUserForRole and getRoleHoldersAsUser require INTERACT_ACROSS_USERS_FULL and // MANAGE_ROLE_HOLDERS permissions to validate cross user role active user and role // holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) .isEqualTo(deviceState.initialUser().userHandle()) assertNoRoleHoldersUsingGetRoleHoldersAsUser() @@ -1576,7 +1672,7 @@ class RoleManagerMultiUserTest { // clearDefaultHoldersForTestForAllUsers and clearRoleVisibleForTestForAllUsers require // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user // role active user and role holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { clearDefaultHoldersForTestForAllUsers() clearRoleVisibleForTestForAllUsers() } @@ -1645,7 +1741,12 @@ class RoleManagerMultiUserTest { getUiDevice().waitForIdle() // CollapsingToolbar title can't be found by text, so using description instead. - assertNull(waitFindObjectOrNull(By.desc(PROFILE_GROUP_EXCLUSIVITY_ROLE_LABEL))) + assertNull( + waitFindObjectOrNull( + By.desc(PROFILE_GROUP_EXCLUSIVITY_ROLE_LABEL), + IDLE_TIMEOUT_MILLIS, + ) + ) pressBack() pressBack() @@ -1681,7 +1782,12 @@ class RoleManagerMultiUserTest { getUiDevice().waitForIdle() // CollapsingToolbar title can't be found by text, so using description instead. - assertNull(waitFindObjectOrNull(By.desc(PROFILE_GROUP_EXCLUSIVITY_ROLE_LABEL))) + assertNull( + waitFindObjectOrNull( + By.desc(PROFILE_GROUP_EXCLUSIVITY_ROLE_LABEL), + IDLE_TIMEOUT_MILLIS, + ) + ) pressBack() pressBack() @@ -1816,7 +1922,8 @@ class RoleManagerMultiUserTest { if (isWatch) { assertNull( waitFindObjectOrNull( - By.clickable(true).checked(true).hasDescendant(By.text(targetAppLabel)) + By.clickable(true).checked(true).hasDescendant(By.text(targetAppLabel)), + IDLE_TIMEOUT_MILLIS, ) ) } else { @@ -1824,7 +1931,8 @@ class RoleManagerMultiUserTest { waitFindObjectOrNull( By.clickable(true) .hasDescendant(By.checkable(true).checked(true)) - .hasDescendant(By.text(targetAppLabel)) + .hasDescendant(By.text(targetAppLabel)), + IDLE_TIMEOUT_MILLIS, ) ) } @@ -1895,7 +2003,8 @@ class RoleManagerMultiUserTest { if (isWatch) { assertNull( waitFindObjectOrNull( - By.clickable(true).checked(true).hasDescendant(By.text(targetAppLabel)) + By.clickable(true).checked(true).hasDescendant(By.text(targetAppLabel)), + IDLE_TIMEOUT_MILLIS, ) ) } else { @@ -1903,7 +2012,8 @@ class RoleManagerMultiUserTest { waitFindObjectOrNull( By.clickable(true) .hasDescendant(By.checkable(true).checked(true)) - .hasDescendant(By.text(targetAppLabel)) + .hasDescendant(By.text(targetAppLabel)), + IDLE_TIMEOUT_MILLIS, ) ) } @@ -1934,7 +2044,7 @@ class RoleManagerMultiUserTest { // setDefaultHoldersForTestForAllUsers and setRoleVisibleForTestForAllUsers require // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user // role active user and role holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { // Set test default role holder. Ensures fallbacks to a default holder setDefaultHoldersForTestForAllUsers() setRoleVisibleForTestForAllUsers() @@ -1961,7 +2071,7 @@ class RoleManagerMultiUserTest { // getActiveUserForRole and getRoleHoldersAsUser require INTERACT_ACROSS_USERS_FULL and // MANAGE_ROLE_HOLDERS permissions to validate cross user role active user and role // holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { assertThat(roleManager.getActiveUserForRole(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME)) .isEqualTo(targetActiveUser) assertExpectedProfileHasRoleUsingGetRoleHoldersAsUser(targetActiveUser) @@ -1970,7 +2080,7 @@ class RoleManagerMultiUserTest { // clearDefaultHoldersForTestForAllUsers and clearRoleVisibleForTestForAllUsers require // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user // role active user and role holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { clearDefaultHoldersForTestForAllUsers() clearRoleVisibleForTestForAllUsers() } @@ -1991,7 +2101,7 @@ class RoleManagerMultiUserTest { // setDefaultHoldersForTestForAllUsers and setRoleVisibleForTestForAllUsers require // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user // role active user and role holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { // Set test default role holder. Ensures fallbacks to a default holder setDefaultHoldersForTestForAllUsers() setRoleVisibleForTestForAllUsers() @@ -2016,7 +2126,7 @@ class RoleManagerMultiUserTest { // clearDefaultHoldersForTestForAllUsers and clearRoleVisibleForTestForAllUsers require // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user // role active user and role holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { clearDefaultHoldersForTestForAllUsers() clearRoleVisibleForTestForAllUsers() } @@ -2037,7 +2147,7 @@ class RoleManagerMultiUserTest { // setDefaultHoldersForTestForAllUsers and setRoleVisibleForTestForAllUsers require // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user // role active user and role holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { // Set test default role holder. Ensures fallbacks to a default holder setDefaultHoldersForTestForAllUsers() setRoleVisibleForTestForAllUsers() @@ -2062,17 +2172,15 @@ class RoleManagerMultiUserTest { // clearDefaultHoldersForTestForAllUsers and clearRoleVisibleForTestForAllUsers require // INTERACT_ACROSS_USERS_FULL and MANAGE_ROLE_HOLDERS permissions to validate cross user // role active user and role holder states - permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { _ -> + permissions().withPermission(INTERACT_ACROSS_USERS_FULL, MANAGE_ROLE_HOLDERS).use { clearDefaultHoldersForTestForAllUsers() clearRoleVisibleForTestForAllUsers() } } } - @Throws(java.lang.Exception::class) private fun installAppForAllUsers() { SystemUtil.runShellCommandOrThrow("pm install -r --user all $APP_APK_PATH") - SystemUtil.waitForBroadcasts() } private fun uninstallAppForAllUsers() { @@ -2099,8 +2207,7 @@ class RoleManagerMultiUserTest { } val result: Pair<Int, Intent?> = clickButtonAndWaitForResult(allow) val expectedResult = - if (allow && Objects.equals(targetActiveUser, users().instrumented().userHandle())) - Activity.RESULT_OK + if (allow && targetActiveUser == users().instrumented().userHandle()) Activity.RESULT_OK else Activity.RESULT_CANCELED assertThat(result.first).isEqualTo(expectedResult) @@ -2118,7 +2225,8 @@ class RoleManagerMultiUserTest { } private fun roleRequestNotShown() { - val requestRoleItem = waitFindObjectOrNull(By.textStartsWith(APP_LABEL)) + val requestRoleItem = + waitFindObjectOrNull(By.textStartsWith(APP_LABEL), IDLE_TIMEOUT_MILLIS) assertNull(requestRoleItem) val result: Pair<Int, Intent?> = waitForResult() @@ -2148,9 +2256,9 @@ class RoleManagerMultiUserTest { ) { for (userReference in users().profileGroup(deviceState.initialUser())) { val user = userReference.userHandle() - if (Objects.equals(user, expectedActiveUser)) { - val roleHolders = - roleManager.getRoleHoldersAsUser(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, user) + val roleHolders = + roleManager.getRoleHoldersAsUser(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, user) + if (user == expectedActiveUser) { assertWithMessage( "Expected user ${user.identifier} to have a role holder for " + " $PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME" @@ -2169,9 +2277,7 @@ class RoleManagerMultiUserTest { "Expected user ${user.identifier} to not have a role holder for" + " $PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME" ) - .that( - roleManager.getRoleHoldersAsUser(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, user) - ) + .that(roleHolders) .isEmpty() } } @@ -2183,7 +2289,7 @@ class RoleManagerMultiUserTest { for (userReference in users().profileGroup(deviceState.initialUser())) { val userRoleManager = getRoleManagerForUser(userReference) val user = userReference.userHandle() - if (Objects.equals(user, expectedActiveUser)) { + if (user == expectedActiveUser) { assertWithMessage("Expected default application for user ${user.identifier}") .that( userRoleManager.getDefaultApplication(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME) @@ -2203,7 +2309,7 @@ class RoleManagerMultiUserTest { private fun setDefaultHoldersForTestForAllUsers() { // Set test default role holder. Ensures fallbacks to a default holder for (userRoleManager in - users().profileGroup(deviceState.initialUser()).map { getRoleManagerForUser(it) }) { + users().profileGroup(users().current()).map { getRoleManagerForUser(it) }) { userRoleManager.setDefaultHoldersForTest( PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, listOf(APP_PACKAGE_NAME), @@ -2214,7 +2320,7 @@ class RoleManagerMultiUserTest { private fun clearDefaultHoldersForTestForAllUsers() { // Set test default role holder. Ensures fallbacks to a default holder for (userRoleManager in - users().profileGroup(deviceState.initialUser()).map { getRoleManagerForUser(it) }) { + users().profileGroup(users().current()).map { getRoleManagerForUser(it) }) { userRoleManager.setDefaultHoldersForTest( PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, emptyList(), @@ -2225,7 +2331,7 @@ class RoleManagerMultiUserTest { private fun setRoleVisibleForTestForAllUsers() { // Set test default role holder. Ensures fallbacks to a default holder for (userRoleManager in - users().profileGroup(deviceState.initialUser()).map { getRoleManagerForUser(it) }) { + users().profileGroup(users().current()).map { getRoleManagerForUser(it) }) { userRoleManager.setRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, true) } } @@ -2233,11 +2339,28 @@ class RoleManagerMultiUserTest { private fun clearRoleVisibleForTestForAllUsers() { // Set test default role holder. Ensures fallbacks to a default holder for (userRoleManager in - users().profileGroup(deviceState.initialUser()).map { getRoleManagerForUser(it) }) { + users().profileGroup(users().current()).map { getRoleManagerForUser(it) }) { userRoleManager.setRoleVisibleForTest(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, false) } } + private fun setRoleFallbackEnabledForAllUsers() { + for (userReference in users().profileGroup(users().current())) { + try { + val userRoleManager = getRoleManagerForUser(userReference) + userRoleManager.setRoleFallbackEnabled(PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME, true) + } catch (e: Exception) { + Log.w( + LOG_TAG, + "Encountered error setting fallback enabled for" + + " $PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME@" + + "${userReference.userHandle().identifier}", + e, + ) + } + } + } + private fun getRoleManagerForUser(user: UserReference): RoleManager { val userContext = context().androidContextAsUser(user) return userContext.getSystemService(RoleManager::class.java) @@ -2250,7 +2373,10 @@ class RoleManagerMultiUserTest { } companion object { + private val LOG_TAG = RoleManagerMultiUserTest::class.java.simpleName + private const val TIMEOUT_MILLIS: Long = (15 * 1000).toLong() + private const val IDLE_TIMEOUT_MILLIS: Long = (2 * 1000).toLong() private const val PROFILE_GROUP_EXCLUSIVITY_ROLE_NAME = RoleManager.ROLE_RESERVED_FOR_TESTING_PROFILE_GROUP_EXCLUSIVITY private const val PROFILE_GROUP_EXCLUSIVITY_ROLE_LABEL = diff --git a/tests/cts/safetycenter/AndroidTest.xml b/tests/cts/safetycenter/AndroidTest.xml index 6d8c3069c..ed161f0b6 100644 --- a/tests/cts/safetycenter/AndroidTest.xml +++ b/tests/cts/safetycenter/AndroidTest.xml @@ -47,6 +47,10 @@ <!-- Disable syncing to prevent overwriting flags during testing. --> <option name="run-command" value="device_config set_sync_disabled_for_tests persistent" /> <option name="teardown-command" value="device_config set_sync_disabled_for_tests none" /> + <!-- Belt-and-braces attempt to dismiss keyguard. Tradefed should have already done this + for us, but this is a precaution in an attempt to mitigate b/379620557. --> + <option name="run-command" value="input keyevent KEYCODE_WAKEUP" /> + <option name="run-command" value="wm dismiss-keyguard" /> <!-- Dismiss any system dialogs (e.g. crashes, ANR). --> <option name="run-command" value="am broadcast -a android.intent.action.CLOSE_SYSTEM_DIALOGS --receiver-foreground" /> </target_preparer> diff --git a/tests/functional/safetycenter/multiusers/AndroidTest.xml b/tests/functional/safetycenter/multiusers/AndroidTest.xml index 20032357a..bfb7fdbf2 100644 --- a/tests/functional/safetycenter/multiusers/AndroidTest.xml +++ b/tests/functional/safetycenter/multiusers/AndroidTest.xml @@ -47,6 +47,10 @@ <!-- Disable syncing to prevent overwriting flags during testing. --> <option name="run-command" value="device_config set_sync_disabled_for_tests persistent" /> <option name="teardown-command" value="device_config set_sync_disabled_for_tests none" /> + <!-- Belt-and-braces attempt to dismiss keyguard. Tradefed should have already done this + for us, but this is a precaution in an attempt to mitigate b/379620557. --> + <option name="run-command" value="input keyevent KEYCODE_WAKEUP" /> + <option name="run-command" value="wm dismiss-keyguard" /> <!-- Dismiss any system dialogs (e.g. crashes, ANR). --> <option name="run-command" value="am broadcast -a android.intent.action.CLOSE_SYSTEM_DIALOGS --receiver-foreground" /> </target_preparer> diff --git a/tests/functional/safetycenter/safetycenteractivity/AndroidTest.xml b/tests/functional/safetycenter/safetycenteractivity/AndroidTest.xml index a1826653f..ee79dcd2a 100644 --- a/tests/functional/safetycenter/safetycenteractivity/AndroidTest.xml +++ b/tests/functional/safetycenter/safetycenteractivity/AndroidTest.xml @@ -47,6 +47,10 @@ <!-- Disable syncing to prevent overwriting flags during testing. --> <option name="run-command" value="device_config set_sync_disabled_for_tests persistent" /> <option name="teardown-command" value="device_config set_sync_disabled_for_tests none" /> + <!-- Belt-and-braces attempt to dismiss keyguard. Tradefed should have already done this + for us, but this is a precaution in an attempt to mitigate b/379620557. --> + <option name="run-command" value="input keyevent KEYCODE_WAKEUP" /> + <option name="run-command" value="wm dismiss-keyguard" /> <!-- Dismiss any system dialogs (e.g. crashes, ANR). --> <option name="run-command" value="am broadcast -a android.intent.action.CLOSE_SYSTEM_DIALOGS --receiver-foreground" /> </target_preparer> diff --git a/tests/functional/safetycenter/singleuser/AndroidTest.xml b/tests/functional/safetycenter/singleuser/AndroidTest.xml index af040eb6f..f778ca93e 100644 --- a/tests/functional/safetycenter/singleuser/AndroidTest.xml +++ b/tests/functional/safetycenter/singleuser/AndroidTest.xml @@ -47,8 +47,8 @@ <!-- Disable syncing to prevent overwriting flags during testing. --> <option name="run-command" value="device_config set_sync_disabled_for_tests persistent" /> <option name="teardown-command" value="device_config set_sync_disabled_for_tests none" /> - <!-- TODO(b/379928062): Ensure device not on lockscreen. Reassess when keyguard bug is - closed --> + <!-- Belt-and-braces attempt to dismiss keyguard. Tradefed should have already done this + for us, but this is a precaution in an attempt to mitigate b/379620557. --> <option name="run-command" value="input keyevent KEYCODE_WAKEUP" /> <option name="run-command" value="wm dismiss-keyguard" /> <!-- Dismiss any system dialogs (e.g. crashes, ANR). --> diff --git a/tests/functional/safetycenter/subpages/AndroidTest.xml b/tests/functional/safetycenter/subpages/AndroidTest.xml index c3245e9d7..ac493841f 100644 --- a/tests/functional/safetycenter/subpages/AndroidTest.xml +++ b/tests/functional/safetycenter/subpages/AndroidTest.xml @@ -47,6 +47,10 @@ <!-- Disable syncing to prevent overwriting flags during testing. --> <option name="run-command" value="device_config set_sync_disabled_for_tests persistent" /> <option name="teardown-command" value="device_config set_sync_disabled_for_tests none" /> + <!-- Belt-and-braces attempt to dismiss keyguard. Tradefed should have already done this + for us, but this is a precaution in an attempt to mitigate b/379620557. --> + <option name="run-command" value="input keyevent KEYCODE_WAKEUP" /> + <option name="run-command" value="wm dismiss-keyguard" /> <!-- Dismiss any system dialogs (e.g. crashes, ANR). --> <option name="run-command" value="am broadcast -a android.intent.action.CLOSE_SYSTEM_DIALOGS --receiver-foreground" /> </target_preparer> diff --git a/tests/hostside/safetycenter/AndroidTest.xml b/tests/hostside/safetycenter/AndroidTest.xml index a28b70c3c..41f0bcc40 100644 --- a/tests/hostside/safetycenter/AndroidTest.xml +++ b/tests/hostside/safetycenter/AndroidTest.xml @@ -32,6 +32,10 @@ <!-- Disable syncing to prevent overwriting flags during testing. --> <option name="run-command" value="device_config set_sync_disabled_for_tests persistent" /> <option name="teardown-command" value="device_config set_sync_disabled_for_tests none" /> + <!-- Belt-and-braces attempt to dismiss keyguard. Tradefed should have already done this + for us, but this is a precaution in an attempt to mitigate b/379620557. --> + <option name="run-command" value="input keyevent KEYCODE_WAKEUP" /> + <option name="run-command" value="wm dismiss-keyguard" /> <!-- Dismiss any system dialogs (e.g. crashes, ANR). --> <option name="run-command" value="am broadcast -a android.intent.action.CLOSE_SYSTEM_DIALOGS --receiver-foreground" /> </target_preparer> |