summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--PermissionController/res/values-ar/strings.xml4
-rw-r--r--PermissionController/res/values-cs/strings.xml2
-rw-r--r--PermissionController/res/values-hu/strings.xml2
-rw-r--r--PermissionController/res/values-ja/strings.xml4
-rw-r--r--PermissionController/res/values-mk/strings.xml2
-rw-r--r--PermissionController/res/values-nb/strings.xml2
-rw-r--r--PermissionController/res/values-pl/strings.xml2
-rw-r--r--PermissionController/res/values-ru-v33/strings.xml2
-rw-r--r--PermissionController/res/values/strings.xml16
-rw-r--r--PermissionController/res/xml/roles.xml2
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/model/Role.java33
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java2
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/util/UserUtils.java12
-rw-r--r--PermissionController/src/com/android/permissioncontroller/ecm/EnhancedConfirmationDialogActivity.kt15
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/Role.md7
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java28
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppConfirmationDialogFragment.java26
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppListChildFragment.java8
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/RequestRoleFragment.java7
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/RoleApplicationPreference.java6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/RolePreference.java6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoRadioPreference.java17
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoRolePreference.java17
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/auto/AutoSwitchPreference.java16
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/behavior/v35/WalletRoleUiBehavior.java53
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/handheld/HandheldRadioPreference.java17
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/handheld/HandheldRolePreference.java17
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/specialappaccess/handheld/HandheldSwitchPreference.java16
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRoleApplicationPreference.kt16
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/ui/wear/WearRolePreference.kt19
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/SafetyCenterFragment.kt13
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/IssueUiData.kt27
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt41
-rw-r--r--PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/SafetyCenterUiData.kt24
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/safetycenter/ui/model/SafetyCenterUiDataTest.kt212
-rw-r--r--SafetyCenter/OWNERS1
-rw-r--r--SafetyCenter/Resources/res/values-mk-v35/strings.xml2
-rw-r--r--SafetyCenter/Resources/res/values-mk/strings.xml4
-rw-r--r--service/java/com/android/permission/util/UserUtils.java30
-rw-r--r--service/java/com/android/role/RoleService.java3
-rw-r--r--service/java/com/android/safetycenter/UserProfileGroup.java5
-rw-r--r--tests/cts/permission/src/android/permission/cts/DevicePermissionsTest.kt182
-rw-r--r--tests/cts/permissionpolicy/res/raw/android_manifest.xml12
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/BaseUsePermissionTest.kt6
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionDecisionsTest.kt25
-rw-r--r--tests/cts/permissionui/src/android/permissionui/cts/PermissionSplitTest.kt10
-rw-r--r--tests/cts/rolemultiuser/src/android/app/rolemultiuser/cts/RoleManagerMultiUserTest.kt236
-rw-r--r--tests/cts/safetycenter/AndroidTest.xml4
-rw-r--r--tests/functional/safetycenter/multiusers/AndroidTest.xml4
-rw-r--r--tests/functional/safetycenter/safetycenteractivity/AndroidTest.xml4
-rw-r--r--tests/functional/safetycenter/singleuser/AndroidTest.xml4
-rw-r--r--tests/functional/safetycenter/subpages/AndroidTest.xml4
-rw-r--r--tests/hostside/safetycenter/AndroidTest.xml4
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">"‏هل تريد السماح لـ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى الصور والوسائط على &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgrouprequest_contacts" msgid="8391550064551053695">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى جهات الاتصال؟"</string>
<string name="permgrouprequest_device_aware_contacts" msgid="731025863972535928">"‏هل تريد السماح لـ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى جهات اتصالك على &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;؟"</string>
- <string name="permgrouprequest_location" msgid="6990232580121067883">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى الموقع الجغرافي لهذا الجهاز؟"</string>
+ <string name="permgrouprequest_location" msgid="6990232580121067883">"‏هل مطلوب السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى الموقع الجغرافي لهذا الجهاز؟"</string>
<string name="permgrouprequest_device_aware_location" msgid="6075412127429878638">"‏هل تريد السماح لـ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى الموقع الجغرافي الخاص بـ &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgrouprequestdetail_location" msgid="2635935335778429894">"لن يكون بإمكان التطبيق الوصول إلى الموقع الجغرافي إلا عند استخدامك لهذا التطبيق."</string>
<string name="permgroupbackgroundrequest_location" msgid="1085680897265734809">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى الموقع الجغرافي لهذا الجهاز؟"</string>
@@ -495,7 +495,7 @@
<string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"تقريبي"</string>
<string name="permgrouprequest_calendar" msgid="1493150855673603806">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى التقويم؟"</string>
<string name="permgrouprequest_device_aware_calendar" msgid="7161929851377463612">"‏هل تريد السماح لـ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى تقويمك على &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;؟"</string>
- <string name="permgrouprequest_sms" msgid="5672063688745420991">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بإرسال رسائل 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">"‏هل تريد السماح لـ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بإرسال الرسائل القصيرة وعرضها على &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;؟"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"‏هل تريد السماح لتطبيق &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى الصور والوسائط والملفات على جهازك؟"</string>
<string name="permgrouprequest_device_aware_storage" msgid="6933251810928606636">"‏هل تريد السماح لـ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بالوصول إلى الصور والوسائط والملفات على &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;؟"</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) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; számára, hogy hozzáférjen a naptárhoz?"</string>
<string name="permgrouprequest_device_aware_calendar" msgid="7161929851377463612">"Engedélyezi a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; számára, hogy hozzáférjen a naptárához ezen az eszközön: &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>’s&lt;/b&gt;?"</string>
- <string name="permgrouprequest_sms" msgid="5672063688745420991">"Engedélyezi a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; számára, hogy SMS-eket küldhessen és tekinthessen meg?"</string>
+ <string name="permgrouprequest_sms" msgid="5672063688745420991">"Engedélyezi a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 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) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; számára az SMS-ek küldését és megtekintését ezen az eszközön: &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</string>
<string name="permgrouprequest_storage" msgid="8717773092518621602">"Engedélyezi a(z) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; 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) &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; számára, hogy fotókhoz, médiatartalmakhoz és fájlokhoz férjen hozzá ezen az eszközön: &lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;?"</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">"&lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;の位置情報に対する &lt;b&gt;<xliff:g id="APP_NAME">&lt;b&gt;%1$s&lt;/b&gt;</xliff:g>&lt;/b&gt; のアクセス権を「おおよそ」から「正確」に変更しますか?"</string>
<string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"このデバイスのおおよその位置情報へのアクセスを &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
<string name="permgrouprequest_device_aware_coarselocation" msgid="8367540370912066757">"&lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;のおおよその位置情報へのアクセスを &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</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">"カレンダーへのアクセスを「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
<string name="permgrouprequest_device_aware_calendar" msgid="7161929851377463612">"&lt;b&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/b&gt;内のカレンダーへのアクセスを &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
<string name="permgrouprequest_sms" msgid="5672063688745420991">"SMS メッセージの送信と表示を「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</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-&amp;shy;standard)"</string>
+ <string name="default_app_system_default" msgid="6218386768175513760">"(System-&amp;#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>